# This shell script emits a C file. -*- C -*- # It does some substitutions. cat >em_${EMULATION_NAME}.c <the_bfd = bfd_create ("linker stubs", output_bfd); if (stub_file->the_bfd == (bfd *) NULL || ! bfd_set_arch_mach (stub_file->the_bfd, bfd_get_arch (output_bfd), bfd_get_mach (output_bfd))) { einfo ("%X%P: can not create BFD: %E"); return; } stub_sec = bfd_make_section_old_way (stub_file->the_bfd, ".text"); stub_toc_sec = bfd_make_section_old_way (stub_file->the_bfd, ".toc"); if (stub_sec == (asection *) NULL || stub_toc_sec == (asection *) NULL || ! bfd_set_section_flags (stub_file->the_bfd, stub_sec, (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_RELOC | SEC_IN_MEMORY)) || ! bfd_set_section_flags (stub_file->the_bfd, stub_toc_sec, (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_RELOC | SEC_IN_MEMORY))) { einfo ("%X%P: can not create stub sections: %E"); return; } ldlang_add_file (stub_file); } /* This is called after the input sections have been attached to the output sections but before the output section sizes have been set. We can identify the required stubs because they are undefined symbols beginning with ".". For each such symbol, we build a stub in the .text section. */ static void gld${EMULATION_NAME}_before_allocation () { bfd_link_hash_traverse (link_info.hash, gld${EMULATION_NAME}_check_symbol, (PTR) NULL); } /* If a particular symbol is undefined and starts with a ".", then we need to make a stub for it. */ /*ARGSUSED*/ static boolean gld${EMULATION_NAME}_check_symbol (h, info) struct bfd_link_hash_entry *h; PTR info; { bfd *stub_bfd; bfd_byte *p; arelent *r; struct bfd_link_hash_entry *hnew; asymbol *sym; if (h->type != bfd_link_hash_undefined || h->root.string[0] != '.') return true; stub_bfd = stub_sec->owner; /* Define this symbol to be the current location in stub_sec. */ h->type = bfd_link_hash_defined; h->u.def.value = bfd_section_size (stub_bfd, stub_sec); h->u.def.section = stub_sec; /* We want to add this: LONG (0x81820000) lwz r12,{TOC index}(r2) LONG (0x90410014) stw r2,20(r1) LONG (0x800c0000) lwz r0,0(r12) LONG (0x804c0004) lwz r2,4(r12) LONG (0x7c0903a6) mtctr r0 LONG (0x4e800420) bctr LONG (0) Traceback table LONG (0xc8000) LONG (0) */ if (! bfd_set_section_size (stub_bfd, stub_sec, h->u.def.value + 9 * 4)) { einfo ("%P%X: can not set section size: %E"); return false; } stub_sec->contents = ((bfd_byte *) xrealloc ((PTR) stub_sec->contents, bfd_section_size (stub_bfd, stub_sec))); p = stub_sec->contents + h->u.def.value; bfd_put_32 (stub_bfd, (bfd_vma) 0x81820000 + bfd_section_size (stub_bfd, stub_toc_sec), p); p += 4; bfd_put_32 (stub_bfd, (bfd_vma) 0x90410014, p); p += 4; bfd_put_32 (stub_bfd, (bfd_vma) 0x800c0000, p); p += 4; bfd_put_32 (stub_bfd, (bfd_vma) 0x804c0004, p); p += 4; bfd_put_32 (stub_bfd, (bfd_vma) 0x7c0903a6, p); p += 4; bfd_put_32 (stub_bfd, (bfd_vma) 0x4e800420, p); p += 4; bfd_put_32 (stub_bfd, (bfd_vma) 0, p); p += 4; bfd_put_32 (stub_bfd, (bfd_vma) 0xc8000, p); p += 4; bfd_put_32 (stub_bfd, (bfd_vma) 0, p); /* Add an undefined symbol for the TOC reference. This is the name without the leading ".". */ hnew = bfd_link_hash_lookup (link_info.hash, h->root.string + 1, true, false, true); if (hnew == (struct bfd_link_hash_entry *) NULL) einfo ("%P%F: bfd_link_hash_lookup failed: %E"); if (hnew->type == bfd_link_hash_new) { hnew->type = bfd_link_hash_undefined; hnew->u.undef.abfd = stub_bfd; bfd_link_add_undef (link_info.hash, hnew); } /* Add a relocation entry for the TOC reference in the first instruction. */ ++stub_sec->reloc_count; stub_sec->relocation = ((arelent *) xrealloc ((PTR) stub_sec->relocation, (stub_sec->reloc_count * sizeof (arelent)))); r = &stub_sec->relocation[stub_sec->reloc_count - 1]; r->sym_ptr_ptr = stub_toc_sec->symbol_ptr_ptr; r->address = h->u.def.value; if (stub_bfd->xvec->byteorder_big_p) r->address += 2; r->addend = 0; r->howto = bfd_reloc_type_lookup (stub_bfd, BFD_RELOC_PPC_TOC16); if (r->howto == (reloc_howto_type *) NULL) einfo ("%P%F: no howto for TOC reference: %E"); /* Add a relocation entry in the TOC section. */ ++stub_toc_sec->reloc_count; stub_toc_sec->relocation = ((arelent *) xrealloc ((PTR) stub_toc_sec->relocation, (stub_toc_sec->reloc_count * sizeof (arelent)))); r = &stub_toc_sec->relocation[stub_toc_sec->reloc_count - 1]; sym = bfd_make_empty_symbol (stub_bfd); sym->name = hnew->root.string; sym->value = 0; sym->flags = BSF_NO_FLAGS; sym->section = &bfd_und_section; sym->udata = NULL; /* FIXME! */ ((struct generic_link_hash_entry *) hnew)->sym = sym; r->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); *r->sym_ptr_ptr = sym; r->address = bfd_section_size (stub_bfd, stub_toc_sec); r->addend = 0; r->howto = bfd_reloc_type_lookup (stub_bfd, BFD_RELOC_32); if (r->howto == (reloc_howto_type *) NULL) einfo ("%P%F: no howto for TOC entry: %E"); /* Add more space to the .toc section. */ if (! bfd_set_section_size (stub_bfd, stub_toc_sec, bfd_section_size (stub_bfd, stub_toc_sec) + 4)) { einfo ("%P%X: can not set section size: %E"); return false; } stub_toc_sec->contents = ((bfd_byte *) xrealloc ((PTR) stub_toc_sec->contents, bfd_section_size (stub_bfd, stub_toc_sec))); bfd_put_32 (stub_bfd, (bfd_vma) 0, (stub_toc_sec->contents + bfd_section_size (stub_bfd, stub_toc_sec) - 4)); return true; } static char * gld${EMULATION_NAME}_get_script(isfile) int *isfile; EOF if test -n "$COMPILE_IN" then # Scripts compiled in. # sed commands to quote an ld script as a C string. sc='s/["\\]/\\&/g s/$/\\n\\/ 1s/^/"/ $s/$/n"/ ' cat >>em_${EMULATION_NAME}.c <>em_${EMULATION_NAME}.c <>em_${EMULATION_NAME}.c <