1214571Sdim# This shell script emits a C file. -*- C -*- 2214571Sdim# Copyright 2006, 2007 Free Software Foundation, Inc. 3214571Sdim# 4214571Sdim# This file is part of GLD, the Gnu Linker. 5214571Sdim# 6214571Sdim# This program is free software; you can redistribute it and/or modify 7214571Sdim# it under the terms of the GNU General Public License as published by 8214571Sdim# the Free Software Foundation; either version 2 of the License, or 9214571Sdim# (at your option) any later version. 10214571Sdim# 11214571Sdim# This program is distributed in the hope that it will be useful, 12214571Sdim# but WITHOUT ANY WARRANTY; without even the implied warranty of 13214571Sdim# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14214571Sdim# GNU General Public License for more details. 15214571Sdim# 16214571Sdim# You should have received a copy of the GNU General Public License along 17214571Sdim# with this program; if not, write to the Free Software Foundation, Inc., 18214571Sdim# 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. 19214571Sdim# 20214571Sdim 21214571Sdim# This file is sourced from elf32.em, and defines extra spu specific 22214571Sdim# features. 23214571Sdim# 24214571Sdimcat >>e${EMULATION_NAME}.c <<EOF 25214571Sdim#include "ldctor.h" 26214571Sdim#include "elf32-spu.h" 27214571Sdim 28214571Sdim/* Non-zero if no overlay processing should be done. */ 29214571Sdimstatic int no_overlays = 0; 30214571Sdim 31214571Sdim/* Non-zero if we want stubs on all calls out of overlay regions. */ 32214571Sdimstatic int non_overlay_stubs = 0; 33214571Sdim 34214571Sdim/* Whether to emit symbols for stubs. */ 35214571Sdimstatic int emit_stub_syms = 0; 36214571Sdim 37214571Sdim/* Non-zero to perform stack space analysis. */ 38214571Sdimstatic int stack_analysis = 0; 39214571Sdim 40214571Sdim/* Whether to emit symbols with stack requirements for each function. */ 41214571Sdimstatic int emit_stack_syms = 0; 42214571Sdim 43214571Sdim/* Range of valid addresses for loadable sections. */ 44214571Sdimstatic bfd_vma local_store_lo = 0; 45214571Sdimstatic bfd_vma local_store_hi = 0x3ffff; 46214571Sdim 47214571Sdimstatic const char ovl_mgr[] = { 48214571SdimEOF 49214571Sdim 50214571Sdim../binutils/bin2c < ${srcdir}/emultempl/spu_ovl.o >> e${EMULATION_NAME}.c 51214571Sdim 52214571Sdimcat >>e${EMULATION_NAME}.c <<EOF 53214571Sdim}; 54214571Sdim 55214571Sdimstatic const struct _ovl_stream ovl_mgr_stream = { 56214571Sdim ovl_mgr, 57214571Sdim ovl_mgr + sizeof (ovl_mgr) 58214571Sdim}; 59214571Sdim 60214571Sdimstatic asection *toe = NULL; 61214571Sdim 62214571Sdim 63214571Sdimstatic int 64214571Sdimis_spu_target (void) 65214571Sdim{ 66214571Sdim extern const bfd_target bfd_elf32_spu_vec; 67214571Sdim 68214571Sdim return link_info.hash->creator == &bfd_elf32_spu_vec; 69214571Sdim} 70214571Sdim 71214571Sdim/* Create our note section. */ 72214571Sdim 73214571Sdimstatic void 74214571Sdimspu_after_open (void) 75214571Sdim{ 76214571Sdim if (is_spu_target () 77214571Sdim && !link_info.relocatable 78214571Sdim && link_info.input_bfds != NULL 79214571Sdim && !spu_elf_create_sections (output_bfd, &link_info, 80214571Sdim stack_analysis, emit_stack_syms)) 81214571Sdim einfo ("%X%P: can not create note section: %E\n"); 82214571Sdim 83214571Sdim gld${EMULATION_NAME}_after_open (); 84214571Sdim} 85214571Sdim 86214571Sdim/* Add section S at the end of output section OUTPUT_NAME. 87214571Sdim 88214571Sdim Really, we should be duplicating ldlang.c map_input_to_output_sections 89214571Sdim logic here, ie. using the linker script to find where the section 90214571Sdim goes. That's rather a lot of code, and we don't want to run 91214571Sdim map_input_to_output_sections again because most sections are already 92214571Sdim mapped. So cheat, and put the section in a fixed place, ignoring any 93214571Sdim attempt via a linker script to put .stub, .ovtab, and built-in 94214571Sdim overlay manager code somewhere else. */ 95214571Sdim 96214571Sdimstatic void 97214571Sdimspu_place_special_section (asection *s, const char *output_name) 98214571Sdim{ 99214571Sdim lang_output_section_statement_type *os; 100214571Sdim 101214571Sdim os = lang_output_section_find (output_name); 102214571Sdim if (os == NULL) 103214571Sdim { 104214571Sdim const char *save = s->name; 105214571Sdim s->name = output_name; 106214571Sdim gld${EMULATION_NAME}_place_orphan (s); 107214571Sdim s->name = save; 108214571Sdim } 109214571Sdim else 110214571Sdim lang_add_section (&os->children, s, os); 111214571Sdim 112214571Sdim s->output_section->size += s->size; 113214571Sdim} 114214571Sdim 115214571Sdim/* Load built-in overlay manager, and tweak overlay section alignment. */ 116214571Sdim 117214571Sdimstatic void 118214571Sdimspu_elf_load_ovl_mgr (void) 119214571Sdim{ 120214571Sdim lang_output_section_statement_type *os; 121214571Sdim struct elf_link_hash_entry *h; 122214571Sdim 123214571Sdim h = elf_link_hash_lookup (elf_hash_table (&link_info), 124214571Sdim "__ovly_load", FALSE, FALSE, FALSE); 125214571Sdim 126214571Sdim if (h != NULL 127214571Sdim && (h->root.type == bfd_link_hash_defined 128214571Sdim || h->root.type == bfd_link_hash_defweak) 129214571Sdim && h->def_regular) 130214571Sdim { 131214571Sdim /* User supplied __ovly_load. */ 132214571Sdim } 133214571Sdim else if (ovl_mgr_stream.start == ovl_mgr_stream.end) 134214571Sdim einfo ("%F%P: no built-in overlay manager\n"); 135214571Sdim else 136214571Sdim { 137214571Sdim lang_input_statement_type *ovl_is; 138214571Sdim 139214571Sdim ovl_is = lang_add_input_file ("builtin ovl_mgr", 140214571Sdim lang_input_file_is_file_enum, 141214571Sdim NULL); 142214571Sdim 143214571Sdim if (!spu_elf_open_builtin_lib (&ovl_is->the_bfd, &ovl_mgr_stream)) 144214571Sdim einfo ("%X%P: can not open built-in overlay manager: %E\n"); 145214571Sdim else 146214571Sdim { 147214571Sdim asection *in; 148214571Sdim 149214571Sdim if (!load_symbols (ovl_is, NULL)) 150214571Sdim einfo ("%X%P: can not load built-in overlay manager: %E\n"); 151214571Sdim 152214571Sdim /* Map overlay manager sections to output sections. */ 153214571Sdim for (in = ovl_is->the_bfd->sections; in != NULL; in = in->next) 154214571Sdim if ((in->flags & (SEC_ALLOC | SEC_LOAD)) 155214571Sdim == (SEC_ALLOC | SEC_LOAD)) 156214571Sdim spu_place_special_section (in, ".text"); 157214571Sdim } 158214571Sdim } 159214571Sdim 160214571Sdim /* Ensure alignment of overlay sections is sufficient. */ 161214571Sdim for (os = &lang_output_section_statement.head->output_section_statement; 162214571Sdim os != NULL; 163214571Sdim os = os->next) 164214571Sdim if (os->bfd_section != NULL 165214571Sdim && spu_elf_section_data (os->bfd_section) != NULL 166214571Sdim && spu_elf_section_data (os->bfd_section)->ovl_index != 0) 167214571Sdim { 168214571Sdim if (os->bfd_section->alignment_power < 4) 169214571Sdim os->bfd_section->alignment_power = 4; 170214571Sdim 171214571Sdim /* Also ensure size rounds up. */ 172214571Sdim os->block_value = 16; 173214571Sdim } 174214571Sdim} 175214571Sdim 176214571Sdim/* Go find if we need to do anything special for overlays. */ 177214571Sdim 178214571Sdimstatic void 179214571Sdimspu_before_allocation (void) 180214571Sdim{ 181214571Sdim if (is_spu_target () 182214571Sdim && !link_info.relocatable 183214571Sdim && !no_overlays) 184214571Sdim { 185214571Sdim /* Size the sections. This is premature, but we need to know the 186214571Sdim rough layout so that overlays can be found. */ 187214571Sdim expld.phase = lang_mark_phase_enum; 188214571Sdim expld.dataseg.phase = exp_dataseg_none; 189214571Sdim one_lang_size_sections_pass (NULL, TRUE); 190214571Sdim 191214571Sdim /* Find overlays by inspecting section vmas. */ 192214571Sdim if (spu_elf_find_overlays (output_bfd, &link_info)) 193214571Sdim { 194214571Sdim asection *stub, *ovtab; 195214571Sdim 196214571Sdim if (!spu_elf_size_stubs (output_bfd, &link_info, non_overlay_stubs, 197214571Sdim stack_analysis, &stub, &ovtab, &toe)) 198214571Sdim einfo ("%X%P: can not size overlay stubs: %E\n"); 199214571Sdim 200214571Sdim if (stub != NULL) 201214571Sdim { 202214571Sdim spu_place_special_section (stub, ".text"); 203214571Sdim spu_place_special_section (ovtab, ".data"); 204214571Sdim spu_place_special_section (toe, ".toe"); 205214571Sdim 206214571Sdim spu_elf_load_ovl_mgr (); 207214571Sdim } 208214571Sdim } 209214571Sdim 210214571Sdim /* We must not cache anything from the preliminary sizing. */ 211214571Sdim lang_reset_memory_regions (); 212214571Sdim } 213214571Sdim 214214571Sdim gld${EMULATION_NAME}_before_allocation (); 215214571Sdim} 216214571Sdim 217214571Sdim/* Final emulation specific call. */ 218214571Sdim 219214571Sdimstatic void 220214571Sdimgld${EMULATION_NAME}_finish (void) 221214571Sdim{ 222214571Sdim int need_laying_out; 223214571Sdim 224214571Sdim need_laying_out = bfd_elf_discard_info (output_bfd, &link_info); 225214571Sdim 226214571Sdim gld${EMULATION_NAME}_map_segments (need_laying_out); 227214571Sdim 228214571Sdim if (is_spu_target () && local_store_lo < local_store_hi) 229214571Sdim { 230214571Sdim asection *s; 231214571Sdim 232214571Sdim s = spu_elf_check_vma (output_bfd, local_store_lo, local_store_hi); 233214571Sdim if (s != NULL) 234214571Sdim einfo ("%X%P: %A exceeds local store range\n", s); 235214571Sdim } 236214571Sdim 237214571Sdim if (toe != NULL 238214571Sdim && !spu_elf_build_stubs (&link_info, 239214571Sdim emit_stub_syms || link_info.emitrelocations, 240214571Sdim toe)) 241214571Sdim einfo ("%X%P: can not build overlay stubs: %E\n"); 242214571Sdim 243214571Sdim finish_default (); 244214571Sdim} 245214571Sdim 246214571SdimEOF 247214571Sdim 248214571Sdimif grep -q 'ld_elf.*ppc.*_emulation' ldemul-list.h; then 249214571Sdim cat >>e${EMULATION_NAME}.c <<EOF 250214571Sdim#include "filenames.h" 251214571Sdim#include <fcntl.h> 252214571Sdim#include <sys/wait.h> 253214571Sdim 254214571Sdimstruct tflist { 255214571Sdim struct tflist *next; 256214571Sdim char name[9]; 257214571Sdim}; 258214571Sdim 259214571Sdimstatic struct tflist *tmp_file_list; 260214571Sdim 261214571Sdimstatic void clean_tmp (void) 262214571Sdim{ 263214571Sdim for (; tmp_file_list != NULL; tmp_file_list = tmp_file_list->next) 264214571Sdim unlink (tmp_file_list->name); 265214571Sdim} 266214571Sdim 267214571Sdimstatic const char * 268214571Sdimbase_name (const char *path) 269214571Sdim{ 270214571Sdim const char *file = strrchr (path, '/'); 271214571Sdim#ifdef HAVE_DOS_BASED_FILE_SYSTEM 272214571Sdim { 273214571Sdim char *bslash = strrchr (path, '\\\\'); 274214571Sdim 275214571Sdim if (file == NULL || (bslash != NULL && bslash > file)) 276214571Sdim file = bslash; 277214571Sdim if (file == NULL 278214571Sdim && path[0] != '\0' 279214571Sdim && path[1] == ':') 280214571Sdim file = path + 1; 281214571Sdim } 282214571Sdim#endif 283214571Sdim if (file == NULL) 284214571Sdim file = path; 285214571Sdim else 286214571Sdim ++file; 287214571Sdim return file; 288214571Sdim} 289214571Sdim 290214571Sdim/* This function is called when building a ppc32 or ppc64 executable 291214571Sdim to handle embedded spu images. */ 292214571Sdimextern bfd_boolean embedded_spu_file (lang_input_statement_type *, const char *); 293214571Sdim 294214571Sdimbfd_boolean 295214571Sdimembedded_spu_file (lang_input_statement_type *entry, const char *flags) 296214571Sdim{ 297214571Sdim const char *cmd[6]; 298214571Sdim const char *sym; 299214571Sdim char *handle, *p; 300214571Sdim struct tflist *tf; 301214571Sdim char *oname; 302214571Sdim int fd; 303214571Sdim pid_t pid; 304214571Sdim int status; 305214571Sdim union lang_statement_union **old_stat_tail; 306214571Sdim union lang_statement_union **old_file_tail; 307214571Sdim union lang_statement_union *new_ent; 308214571Sdim lang_input_statement_type *search; 309214571Sdim 310214571Sdim if (entry->the_bfd->format != bfd_object 311214571Sdim || strcmp (entry->the_bfd->xvec->name, "elf32-spu") != 0 312214571Sdim || (entry->the_bfd->tdata.elf_obj_data->elf_header->e_type != ET_EXEC 313214571Sdim && entry->the_bfd->tdata.elf_obj_data->elf_header->e_type != ET_DYN)) 314214571Sdim return FALSE; 315214571Sdim 316214571Sdim /* Use the filename as the symbol marking the program handle struct. */ 317214571Sdim sym = base_name (entry->the_bfd->filename); 318214571Sdim 319214571Sdim handle = xstrdup (sym); 320214571Sdim for (p = handle; *p; ++p) 321214571Sdim if (!(ISALNUM (*p) || *p == '$' || *p == '.')) 322214571Sdim *p = '_'; 323214571Sdim 324214571Sdim if (tmp_file_list == NULL) 325214571Sdim atexit (clean_tmp); 326214571Sdim tf = xmalloc (sizeof (*tf)); 327214571Sdim tf->next = tmp_file_list; 328214571Sdim tmp_file_list = tf; 329214571Sdim oname = tf->name; 330214571Sdim memcpy (tf->name, "ldXXXXXX", sizeof (tf->name)); 331214571Sdim 332214571Sdim#ifdef HAVE_MKSTEMP 333214571Sdim fd = mkstemp (oname); 334214571Sdim#else 335214571Sdim oname = mktemp (oname); 336214571Sdim if (oname == NULL) 337214571Sdim return FALSE; 338214571Sdim fd = open (oname, O_RDWR | O_CREAT | O_EXCL, 0600); 339214571Sdim#endif 340214571Sdim if (fd == -1) 341214571Sdim return FALSE; 342214571Sdim close (fd); 343214571Sdim 344214571Sdim for (search = (lang_input_statement_type *) input_file_chain.head; 345214571Sdim search != NULL; 346214571Sdim search = (lang_input_statement_type *) search->next_real_file) 347214571Sdim { 348214571Sdim const char *infile = base_name (search->filename); 349214571Sdim 350214571Sdim if (infile != NULL 351214571Sdim && strncmp (infile, "crtbegin", 8) == 0) 352214571Sdim { 353214571Sdim if (infile[8] == 'S') 354214571Sdim flags = concat (flags, " -fPIC", NULL); 355214571Sdim else if (infile[8] == 'T') 356214571Sdim flags = concat (flags, " -fpie", NULL); 357214571Sdim break; 358214571Sdim } 359214571Sdim } 360214571Sdim 361214571Sdim /* Use fork() and exec() rather than system() so that we don't 362214571Sdim need to worry about quoting args. */ 363214571Sdim cmd[0] = EMBEDSPU; 364214571Sdim cmd[1] = flags; 365214571Sdim cmd[2] = handle; 366214571Sdim cmd[3] = entry->the_bfd->filename; 367214571Sdim cmd[4] = oname; 368214571Sdim cmd[5] = NULL; 369214571Sdim if (trace_file_tries) 370214571Sdim { 371214571Sdim info_msg (_("running: %s \"%s\" \"%s\" \"%s\" \"%s\"\n"), 372214571Sdim cmd[0], cmd[1], cmd[2], cmd[3], cmd[4]); 373214571Sdim fflush (stdout); 374214571Sdim } 375214571Sdim 376214571Sdim pid = fork (); 377214571Sdim if (pid == -1) 378214571Sdim return FALSE; 379214571Sdim if (pid == 0) 380214571Sdim { 381214571Sdim execvp (cmd[0], (char *const *) cmd); 382214571Sdim if (strcmp ("embedspu", EMBEDSPU) != 0) 383214571Sdim { 384214571Sdim cmd[0] = "embedspu"; 385214571Sdim execvp (cmd[0], (char *const *) cmd); 386214571Sdim } 387214571Sdim perror (cmd[0]); 388214571Sdim _exit (127); 389214571Sdim } 390214571Sdim#ifdef HAVE_WAITPID 391214571Sdim#define WAITFOR(PID, STAT) waitpid (PID, STAT, 0) 392214571Sdim#else 393214571Sdim#define WAITFOR(PID, STAT) wait (STAT) 394214571Sdim#endif 395214571Sdim if (WAITFOR (pid, &status) != pid 396214571Sdim || !WIFEXITED (status) 397214571Sdim || WEXITSTATUS (status) != 0) 398214571Sdim return FALSE; 399214571Sdim#undef WAITFOR 400214571Sdim 401214571Sdim old_stat_tail = stat_ptr->tail; 402214571Sdim old_file_tail = input_file_chain.tail; 403214571Sdim if (lang_add_input_file (oname, lang_input_file_is_file_enum, NULL) == NULL) 404214571Sdim return FALSE; 405214571Sdim 406214571Sdim /* lang_add_input_file put the new list entry at the end of the statement 407214571Sdim and input file lists. Move it to just after the current entry. */ 408214571Sdim new_ent = *old_stat_tail; 409214571Sdim *old_stat_tail = NULL; 410214571Sdim stat_ptr->tail = old_stat_tail; 411214571Sdim *old_file_tail = NULL; 412214571Sdim input_file_chain.tail = old_file_tail; 413214571Sdim new_ent->header.next = entry->header.next; 414214571Sdim entry->header.next = new_ent; 415214571Sdim new_ent->input_statement.next_real_file = entry->next_real_file; 416214571Sdim entry->next_real_file = new_ent; 417214571Sdim 418214571Sdim /* Ensure bfd sections are excluded from the output. */ 419214571Sdim bfd_section_list_clear (entry->the_bfd); 420214571Sdim entry->loaded = TRUE; 421214571Sdim return TRUE; 422214571Sdim} 423214571Sdim 424214571SdimEOF 425214571Sdimfi 426214571Sdim 427214571Sdim# Define some shell vars to insert bits of code into the standard elf 428214571Sdim# parse_args and list_options functions. 429214571Sdim# 430214571SdimPARSE_AND_LIST_PROLOGUE=' 431214571Sdim#define OPTION_SPU_PLUGIN 301 432214571Sdim#define OPTION_SPU_NO_OVERLAYS (OPTION_SPU_PLUGIN + 1) 433214571Sdim#define OPTION_SPU_STUB_SYMS (OPTION_SPU_NO_OVERLAYS + 1) 434214571Sdim#define OPTION_SPU_NON_OVERLAY_STUBS (OPTION_SPU_STUB_SYMS + 1) 435214571Sdim#define OPTION_SPU_LOCAL_STORE (OPTION_SPU_NON_OVERLAY_STUBS + 1) 436214571Sdim#define OPTION_SPU_STACK_ANALYSIS (OPTION_SPU_LOCAL_STORE + 1) 437214571Sdim#define OPTION_SPU_STACK_SYMS (OPTION_SPU_STACK_ANALYSIS + 1) 438214571Sdim' 439214571Sdim 440214571SdimPARSE_AND_LIST_LONGOPTS=' 441214571Sdim { "plugin", no_argument, NULL, OPTION_SPU_PLUGIN }, 442214571Sdim { "no-overlays", no_argument, NULL, OPTION_SPU_NO_OVERLAYS }, 443214571Sdim { "emit-stub-syms", no_argument, NULL, OPTION_SPU_STUB_SYMS }, 444214571Sdim { "extra-overlay-stubs", no_argument, NULL, OPTION_SPU_NON_OVERLAY_STUBS }, 445214571Sdim { "local-store", required_argument, NULL, OPTION_SPU_LOCAL_STORE }, 446214571Sdim { "stack-analysis", no_argument, NULL, OPTION_SPU_STACK_ANALYSIS }, 447214571Sdim { "emit-stack-syms", no_argument, NULL, OPTION_SPU_STACK_SYMS }, 448214571Sdim' 449214571Sdim 450214571SdimPARSE_AND_LIST_OPTIONS=' 451214571Sdim fprintf (file, _("\ 452214571Sdim --plugin Make SPU plugin.\n\ 453214571Sdim --no-overlays No overlay handling.\n\ 454214571Sdim --emit-stub-syms Add symbols on overlay call stubs.\n\ 455214571Sdim --extra-overlay-stubs Add stubs on all calls out of overlay regions.\n\ 456214571Sdim --local-store=lo:hi Valid address range.\n\ 457214571Sdim --stack-analysis Estimate maximum stack requirement.\n\ 458214571Sdim --emit-stack-syms Add __stack_func giving stack needed for each func.\n" 459214571Sdim )); 460214571Sdim' 461214571Sdim 462214571SdimPARSE_AND_LIST_ARGS_CASES=' 463214571Sdim case OPTION_SPU_PLUGIN: 464214571Sdim spu_elf_plugin (1); 465214571Sdim break; 466214571Sdim 467214571Sdim case OPTION_SPU_NO_OVERLAYS: 468214571Sdim no_overlays = 1; 469214571Sdim break; 470214571Sdim 471214571Sdim case OPTION_SPU_STUB_SYMS: 472214571Sdim emit_stub_syms = 1; 473214571Sdim break; 474214571Sdim 475214571Sdim case OPTION_SPU_NON_OVERLAY_STUBS: 476214571Sdim non_overlay_stubs = 1; 477214571Sdim break; 478214571Sdim 479214571Sdim case OPTION_SPU_LOCAL_STORE: 480214571Sdim { 481214571Sdim char *end; 482214571Sdim local_store_lo = strtoul (optarg, &end, 0); 483214571Sdim if (*end == '\'':'\'') 484214571Sdim { 485214571Sdim local_store_hi = strtoul (end + 1, &end, 0); 486214571Sdim if (*end == 0) 487214571Sdim break; 488214571Sdim } 489214571Sdim einfo (_("%P%F: invalid --local-store address range `%s'\''\n"), optarg); 490214571Sdim } 491214571Sdim break; 492214571Sdim 493214571Sdim case OPTION_SPU_STACK_ANALYSIS: 494214571Sdim stack_analysis = 1; 495214571Sdim break; 496214571Sdim 497214571Sdim case OPTION_SPU_STACK_SYMS: 498214571Sdim emit_stack_syms = 1; 499214571Sdim break; 500214571Sdim' 501214571Sdim 502214571SdimLDEMUL_AFTER_OPEN=spu_after_open 503214571SdimLDEMUL_BEFORE_ALLOCATION=spu_before_allocation 504214571SdimLDEMUL_FINISH=gld${EMULATION_NAME}_finish 505