diff options
author | Paul Brook <paul@codesourcery.com> | 2005-07-05 13:25:56 +0000 |
---|---|---|
committer | Paul Brook <paul@codesourcery.com> | 2005-07-05 13:25:56 +0000 |
commit | 9d8504b17f98d4fc4a524395563fa67a4fe8d2bc (patch) | |
tree | ebcd18202ac1d85cf124bfe08e8765dfd4b71f9f /bfd/elf32-ppc.c | |
parent | a0defb2e2351bd85b729ae294d1b1997f9f4f39b (diff) | |
download | ppe42-binutils-9d8504b17f98d4fc4a524395563fa67a4fe8d2bc.tar.gz ppe42-binutils-9d8504b17f98d4fc4a524395563fa67a4fe8d2bc.zip |
2005-05-07 Paul Brook <paul@codesourcery.com>
bfd/
* config.bfd: Add separate case for ppc-vxworks.
* configure: Regenerate.
* configure.in: Include elf-vxworks.lo on ppc targets.
* elf-vxworks.c (elf_vxworks_final_write_processing): Handle
.rela.plt.unloaded.
* elf32-ppc.c: Add VxWorks target vec. Include elf-vxworks.h.
(PLT_ENTRY_SIZE, PLT_INITIAL_ENTRY_SIZE, PLT_SLOT_SIZE): Remove.
(VXWORKS_PLT_ENTRY_SIZE, ppc_elf_vxworks_plt_entry,
ppc_elf_vxworks_pic_plt_entry, VXWORKS_PLT_INITIAL_ENTRY_SIZE,
ppc_elf_vxworks_plt0_entry, ppc_elf_vxworks_pic_plt0_entry,
VXWORKS_PLT_NON_JMP_SLOT_RELOCS, VXWORKS_PLTRESOLVE_RELOCS,
VXWORKS_PLTRESOLVE_RELOCS_SHLIB): New.
(ppc_elf_link_hash_table): Add srelplt2, sgotplt, hgot, hplt,
is_vxworks, plt_entry_size, plt_slot_size, plt_initial_entry_size.
(ppc_elf_link_hash_table_create): Initialize hadtab plt fields.
(ppc_elf_create_got): Create .got.plt for VxWorks.
(ppc_elf_create_dynamic_sections): Create unloaded plt relocation
section for VxWorks.
(ppc_elf_select_plt_layout): Handle VxWorks plt format.
(allocate_got): VxWorks does not need a got header.
(allocate_dynrelocs): Handle VxWorks plt format.
(ppc_elf_size_dynamic_sections): Save _G_O_T_ and _P_L_T_ symbols for
VxWorks. Handle VxWorks plt/got.
(ppc_elf_finish_dynamic_sections): Fill in VxWorks plt.
(ppc_elf_vxworks_special_sections): New.
(ppc_elf_vxworks_link_hash_table_create,
ppc_elf_vxworks_add_symbol_hook,
elf_i386_vxworks_link_output_symbol_hook,
ppc_elf_vxworks_final_write_processing): New functions.
* targets.c (bfd_elf32_powerpc_vxworks_vec): Declare.
(_bfd_target_vector): Use it.
gas/
* config/tc-ppc.c (ppc_target_format): Add VxWorks.
gas/testsuite/
* gas/ppc/altivec.d: Match all powerpc target vecs.
* gas/ppc/booke.d: Ditto.
* gas/ppc/e500.d: Ditto.
ld/
* Makefile.am (ALL_EMULATIONS): Add eelf32ppcvxworks.o.
(eelf32ppcvxworks.o): Add dependencies.
* Makefile.in: Regenerate.
* configure.tgt: Add entry for powerpc-vxworks.
* emulparams/elf32-ppc.c: Mention elf32ppcvxworks.sh in comment.
* emulparams/elf32ppcvxworks.sh: New file.
* emultempl/ppc32elf.em (bfd_elf32_powerpc_vxworks_vec): Declare.
(is_ppc_elf32_vec): New function.
(ppc_after_open, ppc_before_allocation,
gld${EMULATION_NAME}_after_allocation): Use it.
Diffstat (limited to 'bfd/elf32-ppc.c')
-rw-r--r-- | bfd/elf32-ppc.c | 679 |
1 files changed, 622 insertions, 57 deletions
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 071f448524..451e89f9e5 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -32,6 +32,7 @@ #include "elf-bfd.h" #include "elf/ppc.h" #include "elf32-ppc.h" +#include "elf-vxworks.h" /* RELA relocations are used here. */ @@ -52,12 +53,6 @@ static bfd_reloc_status_type ppc_elf_unhandled_reloc #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" /* For old-style PLT. */ -/* The size in bytes of an entry in the procedure linkage table. */ -#define PLT_ENTRY_SIZE 12 -/* The initial size of the plt reserved for the dynamic linker. */ -#define PLT_INITIAL_ENTRY_SIZE 72 -/* The size of the gap between entries in the PLT. */ -#define PLT_SLOT_SIZE 8 /* The number of single-slot PLT entries (the rest use two slots). */ #define PLT_NUM_SINGLE_ENTRIES 8192 @@ -65,6 +60,73 @@ static bfd_reloc_status_type ppc_elf_unhandled_reloc #define GLINK_PLTRESOLVE 16*4 #define GLINK_ENTRY_SIZE 4*4 +/* VxWorks uses its own plt layout, filled in by the static linker. */ + +/* The standard VxWorks PLT entry. */ +#define VXWORKS_PLT_ENTRY_SIZE 32 +static const bfd_vma ppc_elf_vxworks_plt_entry + [VXWORKS_PLT_ENTRY_SIZE / 4] = + { + 0x3d800000, /* lis r12,0 */ + 0x818c0000, /* lwz r12,0(r12) */ + 0x7d8903a6, /* mtctr r12 */ + 0x4e800420, /* bctr */ + 0x39600000, /* li r11,0 */ + 0x48000000, /* b 14 <.PLT0resolve+0x4> */ + 0x60000000, /* nop */ + 0x60000000, /* nop */ + }; +static const bfd_vma ppc_elf_vxworks_pic_plt_entry + [VXWORKS_PLT_ENTRY_SIZE / 4] = + { + 0x3d9e0000, /* addis r12,r30,0 */ + 0x818c0000, /* lwz r12,0(r12) */ + 0x7d8903a6, /* mtctr r12 */ + 0x4e800420, /* bctr */ + 0x39600000, /* li r11,0 */ + 0x48000000, /* b 14 <.PLT0resolve+0x4> 14: R_PPC_REL24 .PLTresolve */ + 0x60000000, /* nop */ + 0x60000000, /* nop */ + }; + +/* The initial VxWorks PLT entry. */ +#define VXWORKS_PLT_INITIAL_ENTRY_SIZE 32 +static const bfd_vma ppc_elf_vxworks_plt0_entry + [VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] = + { + 0x3d800000, /* lis r12,0 */ + 0x398c0000, /* addi r12,r12,0 */ + 0x800c0008, /* lwz r0,8(r12) */ + 0x7c0903a6, /* mtctr r0 */ + 0x818c0004, /* lwz r12,4(r12) */ + 0x4e800420, /* bctr */ + 0x60000000, /* nop */ + 0x60000000, /* nop */ + }; +static const bfd_vma ppc_elf_vxworks_pic_plt0_entry + [VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] = + { + 0x819e0008, /* lwz r12,8(r30) */ + 0x7d8903a6, /* mtctr r12 */ + 0x819e0004, /* lwz r12,4(r30) */ + 0x4e800420, /* bctr */ + 0x60000000, /* nop */ + 0x60000000, /* nop */ + 0x60000000, /* nop */ + 0x60000000, /* nop */ + }; + +/* For executables, we have some additional relocations in + .rela.plt.unloaded, for the kernel loader. */ + +/* The number of non-JMP_SLOT relocations per PLT0 slot. */ +#define VXWORKS_PLT_NON_JMP_SLOT_RELOCS 3 +/* The number of relocations in the PLTResolve slot. */ +#define VXWORKS_PLTRESOLVE_RELOCS 2 +/* The number of relocations in the PLTResolve slot when when creating + a shared library. */ +#define VXWORKS_PLTRESOLVE_RELOCS_SHLIB 0 + /* Some instructions. */ #define ADDIS_11_11 0x3d6b0000 #define ADDIS_11_30 0x3d7e0000 @@ -2293,6 +2355,25 @@ struct ppc_elf_link_hash_table /* Small local sym to section mapping cache. */ struct sym_sec_cache sym_sec; + + /* The (unloaded but important) .rela.plt.unloaded on VxWorks. */ + asection *srelplt2; + + /* The .got.plt section (VxWorks only)*/ + asection *sgotplt; + + /* Short-cuts to frequently used symbols on VxWorks targets. */ + struct elf_link_hash_entry *hgot, *hplt; + + /* True if the target system is VxWorks. */ + int is_vxworks; + + /* The size of PLT entries. */ + int plt_entry_size; + /* The distance between adjacent PLT slots. */ + int plt_slot_size; + /* The size of the first PLT entry. */ + int plt_initial_entry_size; }; /* Get the PPC ELF linker hash table from a link_info structure. */ @@ -2360,10 +2441,16 @@ ppc_elf_link_hash_table_create (bfd *abfd) ret->sdata[1].sym_name = "_SDA2_BASE_"; ret->sdata[1].bss_name = ".sbss2"; + ret->plt_entry_size = 12; + ret->plt_slot_size = 8; + ret->plt_initial_entry_size = 72; + + ret->is_vxworks = 0; + return &ret->elf.root; } -/* The powerpc .got has a blrl instruction in it. Mark it executable. */ +/* Create .got and the related sections. */ static bfd_boolean ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info) @@ -2380,10 +2467,21 @@ ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info) if (s == NULL) abort (); - flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - if (!bfd_set_section_flags (abfd, s, flags)) - return FALSE; + if (htab->is_vxworks) + { + htab->sgotplt = bfd_get_section_by_name (abfd, ".got.plt"); + if (!htab->sgotplt) + abort (); + } + else + { + /* The powerpc .got has a blrl instruction in it. Mark it + executable. */ + flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS + | SEC_IN_MEMORY | SEC_LINKER_CREATED); + if (!bfd_set_section_flags (abfd, s, flags)) + return FALSE; + } flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED | SEC_READONLY); @@ -2441,6 +2539,20 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) return FALSE; } + /* Create the section for VxWorks static plt relocations. */ + if (htab->is_vxworks && !info->shared) + { + s = bfd_make_section (abfd, ".rela.plt.unloaded"); + flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_READONLY + | SEC_LINKER_CREATED); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags) + || ! bfd_set_section_alignment (abfd, s, + get_elf_backend_data (abfd)->s->log_file_align)) + return FALSE; + htab->srelplt2 = s; + } + htab->relplt = bfd_get_section_by_name (abfd, ".rela.plt"); htab->plt = s = bfd_get_section_by_name (abfd, ".plt"); if (s == NULL) @@ -3423,15 +3535,26 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, int force_old_plt) { struct ppc_elf_link_hash_table *htab; + flagword flags; htab = ppc_elf_hash_table (info); if (force_old_plt || !htab->new_plt) htab->old_plt = 1; - if (!htab->old_plt) + if (htab->is_vxworks) { - flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_LINKER_CREATED); + /* The VxWorks PLT is a loaded section with contents. */ + flags = SEC_ALLOC | SEC_CODE | SEC_IN_MEMORY | SEC_LINKER_CREATED + | SEC_HAS_CONTENTS | SEC_LOAD | SEC_READONLY; + + if (htab->plt != NULL + && !bfd_set_section_flags (htab->elf.dynobj, htab->plt, flags)) + return -1; + } + else if (!htab->old_plt) + { + flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS + | SEC_IN_MEMORY | SEC_LINKER_CREATED); /* The new PLT is a loaded section. */ if (htab->plt != NULL @@ -4042,7 +4165,12 @@ allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need) if (htab->old_plt) max_before_header = 32764; - if (need <= htab->got_gap) + if (htab->is_vxworks) + { + where = htab->got->size; + htab->got->size += need; + } + else if (need <= htab->got_gap) { where = max_before_header - htab->got_gap; htab->got_gap -= need; @@ -4103,7 +4231,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { asection *s = htab->plt; - if (!htab->old_plt) + if (!(htab->old_plt || htab->is_vxworks)) { if (!doneone) { @@ -4134,16 +4262,17 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* If this is the first .plt entry, make room for the special first entry. */ if (s->size == 0) - s->size += PLT_INITIAL_ENTRY_SIZE; + s->size += htab->plt_initial_entry_size; /* The PowerPC PLT is actually composed of two parts, the first part is 2 words (for a load and a jump), and then there is a remaining word available at the end. */ - plt_offset = (PLT_INITIAL_ENTRY_SIZE - + (PLT_SLOT_SIZE - * ((s->size - PLT_INITIAL_ENTRY_SIZE) - / PLT_ENTRY_SIZE))); + plt_offset = (htab->plt_initial_entry_size + + (htab->plt_slot_size + * ((s->size + - htab->plt_initial_entry_size) + / htab->plt_entry_size))); /* If this symbol is not defined in a regular file, and we are not generating a shared @@ -4158,12 +4287,15 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) h->root.u.def.value = plt_offset; } - /* Make room for this entry. After the 8192nd - entry, room for two entries is allocated. */ - s->size += PLT_ENTRY_SIZE; - if ((s->size - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE - > PLT_NUM_SINGLE_ENTRIES) - s->size += PLT_ENTRY_SIZE; + /* Make room for this entry. */ + s->size += htab->plt_entry_size; + /* After the 8192nd entry, room for two entries + is allocated. */ + if (!htab->is_vxworks + && (s->size - htab->plt_initial_entry_size) + / htab->plt_entry_size + > PLT_NUM_SINGLE_ENTRIES) + s->size += htab->plt_entry_size; } ent->plt.offset = plt_offset; } @@ -4172,6 +4304,29 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (!doneone) { htab->relplt->size += sizeof (Elf32_External_Rela); + + if (htab->is_vxworks) + { + /* Allocate space for the unloaded relocations. */ + if (!info->shared) + { + if (ent->plt.offset + == (bfd_vma) htab->plt_initial_entry_size) + { + htab->srelplt2->size + += sizeof (Elf32_External_Rela) + * VXWORKS_PLTRESOLVE_RELOCS; + } + + htab->srelplt2->size + += sizeof (Elf32_External_Rela) + * VXWORKS_PLT_NON_JMP_SLOT_RELOCS; + } + + /* Every PLT entry has an associated GOT entry in + .got.plt. */ + htab->sgotplt->size += 4; + } doneone = TRUE; } } @@ -4489,10 +4644,31 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, else htab->tlsld_got.offset = (bfd_vma) -1; + if (htab->is_vxworks) + { + /* Save the GOT and PLT symbols in the hash table for easy access. + Mark them as having relocations; they might not, but we won't + know for sure until we build the GOT in finish_dynamic_symbol. */ + + htab->hgot = elf_link_hash_lookup (elf_hash_table (info), + "_GLOBAL_OFFSET_TABLE_", + FALSE, FALSE, FALSE); + if (htab->hgot) + htab->hgot->indx = -2; + htab->hplt = elf_link_hash_lookup (elf_hash_table (info), + "_PROCEDURE_LINKAGE_TABLE_", + FALSE, FALSE, FALSE); + if (htab->hplt) + htab->hplt->indx = -2; + /* If the PLT is executable then give the symbol function type. */ + if (htab->hplt && htab->plt->flags & SEC_CODE) + htab->hplt->type = STT_FUNC; + } + /* Allocate space for global sym dynamic relocs. */ elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info); - if (htab->got != NULL) + if (htab->got != NULL && !htab->is_vxworks) { unsigned int g_o_t = 32768; @@ -4502,7 +4678,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, g_o_t = htab->got->size; htab->got->size += htab->got_header_size; } - if (htab->old_plt) + if (htab->old_plt && !htab->is_vxworks) g_o_t += 4; htab->elf.hgot->root.u.def.value = g_o_t; @@ -4523,14 +4699,22 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, relocs = FALSE; for (s = htab->elf.dynobj->sections; s != NULL; s = s->next) { + bfd_boolean strip_section = TRUE; + if ((s->flags & SEC_LINKER_CREATED) == 0) continue; if (s == htab->plt || s == htab->glink || s == htab->got + || s == htab->sgotplt || s == htab->sbss) { + /* We'd like to strip these sections if they aren't needed, but if + we've exported dynamic symbols from them we must leave them. + It's too late to tell BFD to get rid of the symbols. */ + if ((s == htab->plt || s == htab->got) && htab->hplt != NULL) + strip_section = FALSE; /* Strip this section if we don't need it; see the comment below. */ } @@ -4569,7 +4753,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, continue; } - if (s->size == 0) + if (s->size == 0 && strip_section) { s->flags |= SEC_EXCLUDE; continue; @@ -6453,38 +6637,171 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, bfd_byte *loc; bfd_vma reloc_index; + if (!(htab->old_plt || htab->is_vxworks)) + reloc_index = ent->plt.offset / 4; + else + { + reloc_index = ((ent->plt.offset - htab->plt_initial_entry_size) + / htab->plt_slot_size); + if (reloc_index > PLT_NUM_SINGLE_ENTRIES + && !htab->is_vxworks) + reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2; + } + /* This symbol has an entry in the procedure linkage table. Set it up. */ - if (htab->old_plt) + if (htab->is_vxworks) { - /* We don't need to fill in the .plt. The ppc dynamic - linker will fill it in. */ + bfd_vma got_offset; + const bfd_vma *plt_entry; + + /* The first three entries in .got.plt are reserved. */ + got_offset = (reloc_index + 3) * 4; + + /* Use the right PLT. */ + plt_entry = info->shared ? ppc_elf_vxworks_pic_plt_entry + : ppc_elf_vxworks_plt_entry; + + /* Fill in the .plt on VxWorks. */ + if (info->shared) + { + bfd_vma got_offset_hi = (got_offset >> 16) + + ((got_offset & 0x8000) >> 15); + + bfd_put_32 (output_bfd, + plt_entry[0] | (got_offset_hi & 0xffff), + htab->plt->contents + ent->plt.offset + 0); + bfd_put_32 (output_bfd, + plt_entry[1] | (got_offset & 0xffff), + htab->plt->contents + ent->plt.offset + 4); + } + else + { + bfd_vma got_loc = (got_offset + + htab->hgot->root.u.def.value + + htab->hgot->root.u.def.section->output_offset + + htab->hgot->root.u.def.section->output_section->vma); + bfd_vma got_loc_hi = (got_loc >> 16) + + ((got_loc & 0x8000) >> 15); + + bfd_put_32 (output_bfd, + plt_entry[0] | (got_loc_hi & 0xffff), + htab->plt->contents + ent->plt.offset + 0); + bfd_put_32 (output_bfd, + plt_entry[1] | (got_loc & 0xffff), + htab->plt->contents + ent->plt.offset + 4); + } + + bfd_put_32 (output_bfd, plt_entry[2], + htab->plt->contents + ent->plt.offset + 8); + bfd_put_32 (output_bfd, plt_entry[3], + htab->plt->contents + ent->plt.offset + 12); + + /* This instruction is an immediate load. The value loaded is + the byte offset of the R_PPC_JMP_SLOT relocation from the + start of the .rela.plt section. The value is stored in the + low-order 16 bits of the load instruction. */ + /* NOTE: It appears that this is now an index rather than a + prescaled offset. */ + bfd_put_32 (output_bfd, + plt_entry[4] | reloc_index, + htab->plt->contents + ent->plt.offset + 16); + /* This instruction is a PC-relative branch whose target is + the start of the PLT section. The address of this branch + instruction is 20 bytes beyond the start of this PLT entry. + The address is encoded in bits 6-29, inclusive. The value + stored is right-shifted by two bits, permitting a 26-bit + offset. */ + bfd_put_32 (output_bfd, + (plt_entry[5] + | (-(ent->plt.offset + 20) & 0x03fffffc)), + htab->plt->contents + ent->plt.offset + 20); + bfd_put_32 (output_bfd, plt_entry[6], + htab->plt->contents + ent->plt.offset + 24); + bfd_put_32 (output_bfd, plt_entry[7], + htab->plt->contents + ent->plt.offset + 28); + + /* Fill in the GOT entry corresponding to this PLT slot with + the address immediately after the the "bctr" instruction + in this PLT entry. */ + bfd_put_32 (output_bfd, (htab->plt->output_section->vma + + htab->plt->output_offset + + ent->plt.offset + 16), + htab->sgotplt->contents + got_offset); + + if (!info->shared) + { + /* Fill in a couple of entries in .rela.plt.unloaded. */ + loc = htab->srelplt2->contents + + ((VXWORKS_PLTRESOLVE_RELOCS + reloc_index + * VXWORKS_PLT_NON_JMP_SLOT_RELOCS) + * sizeof (Elf32_External_Rela)); + + /* Provide the @ha relocation for the first instruction. */ + rela.r_offset = (htab->plt->output_section->vma + + htab->plt->output_offset + + ent->plt.offset + 2); + rela.r_info = ELF32_R_INFO (htab->hgot->indx, + R_PPC_ADDR16_HA); + rela.r_addend = got_offset; + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + loc += sizeof (Elf32_External_Rela); + + /* Provide the @l relocation for the second instruction. */ + rela.r_offset = (htab->plt->output_section->vma + + htab->plt->output_offset + + ent->plt.offset + 6); + rela.r_info = ELF32_R_INFO (htab->hgot->indx, + R_PPC_ADDR16_LO); + rela.r_addend = got_offset; + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + loc += sizeof (Elf32_External_Rela); + + /* Provide a relocation for the GOT entry corresponding to this + PLT slot. Point it at the middle of the .plt entry. */ + rela.r_offset = (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + got_offset); + rela.r_info = ELF32_R_INFO (htab->hplt->indx, + R_PPC_ADDR32); + rela.r_addend = ent->plt.offset + 16; + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + } + + /* VxWorks uses non-standard semantics for R_PPC_JMP_SLOT. + In particular, the offset for the relocation is not the + address of the PLT entry for this function, as specified + by the ABI. Instead, the offset is set to the address of + the GOT slot for this function. See EABI 4.4.4.1. */ + rela.r_offset = (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + got_offset); + } else { - bfd_vma val = (htab->glink_pltresolve + ent->plt.offset - + htab->glink->output_section->vma - + htab->glink->output_offset); - bfd_put_32 (output_bfd, val, - htab->plt->contents + ent->plt.offset); + rela.r_offset = (htab->plt->output_section->vma + + htab->plt->output_offset + + ent->plt.offset); + if (htab->old_plt) + { + /* We don't need to fill in the .plt. The ppc dynamic + linker will fill it in. */ + } + else + { + bfd_vma val = (htab->glink_pltresolve + ent->plt.offset + + htab->glink->output_section->vma + + htab->glink->output_offset); + bfd_put_32 (output_bfd, val, + htab->plt->contents + ent->plt.offset); + } } /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = (htab->plt->output_section->vma - + htab->plt->output_offset - + ent->plt.offset); rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT); rela.r_addend = 0; - if (!htab->old_plt) - reloc_index = ent->plt.offset / 4; - else - { - reloc_index = ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE) - / PLT_SLOT_SIZE); - if (reloc_index > PLT_NUM_SINGLE_ENTRIES) - reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2; - } loc = (htab->relplt->contents + reloc_index * sizeof (Elf32_External_Rela)); bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); @@ -6605,9 +6922,11 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd, #endif /* Mark some specially defined symbols as absolute. */ - if (h == htab->elf.hgot - || strcmp (h->root.root.string, "_DYNAMIC") == 0 - || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0) + if (strcmp (h->root.root.string, "_DYNAMIC") == 0 + || (!htab->is_vxworks + && (h == htab->elf.hgot + || strcmp (h->root.root.string, + "_PROCEDURE_LINKAGE_TABLE_") == 0))) sym->st_shndx = SHN_ABS; return TRUE; @@ -6638,15 +6957,22 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { asection *sdyn; + asection *splt; struct ppc_elf_link_hash_table *htab; bfd_vma got; + bfd * dynobj; #ifdef DEBUG fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n"); #endif htab = ppc_elf_hash_table (info); - sdyn = bfd_get_section_by_name (htab->elf.dynobj, ".dynamic"); + dynobj = elf_hash_table (info)->dynobj; + sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + if (htab->is_vxworks) + splt = bfd_get_section_by_name (dynobj, ".plt"); + else + splt = NULL; got = 0; if (htab->elf.hgot != NULL) @@ -6667,12 +6993,15 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, Elf_Internal_Dyn dyn; asection *s; - bfd_elf32_swap_dyn_in (htab->elf.dynobj, dyncon, &dyn); + bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); switch (dyn.d_tag) { case DT_PLTGOT: - s = htab->plt; + if (htab->is_vxworks) + s = htab->sgotplt; + else + s = htab->plt; dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; break; @@ -6689,6 +7018,15 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, dyn.d_un.d_ptr = got; break; + case DT_RELASZ: + if (htab->is_vxworks) + { + if (htab->relplt) + dyn.d_un.d_ptr -= htab->relplt->size; + break; + } + continue; + default: continue; } @@ -6705,7 +7043,7 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, bfd_vma val; p += elf_hash_table (info)->hgot->root.u.def.value; - if (htab->old_plt) + if (htab->old_plt && !htab->is_vxworks) bfd_put_32 (output_bfd, 0x4e800021 /* blrl */, p - 4); val = 0; @@ -6716,6 +7054,89 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 4; } + /* Fill in the first entry in the VxWorks procedure linkage table. */ + if (splt && splt->size > 0) + { + /* Use the right PLT. */ + static const bfd_vma *plt_entry = NULL; + plt_entry = info->shared ? + ppc_elf_vxworks_pic_plt0_entry : ppc_elf_vxworks_plt0_entry; + + if (!info->shared) + { + bfd_vma got_value = + (htab->hgot->root.u.def.section->output_section->vma + + htab->hgot->root.u.def.section->output_offset + + htab->hgot->root.u.def.value); + bfd_vma got_hi = (got_value >> 16) + ((got_value & 0x8000) >> 15); + + bfd_put_32 (output_bfd, plt_entry[0] | (got_hi & 0xffff), + splt->contents + 0); + bfd_put_32 (output_bfd, plt_entry[1] | (got_value & 0xffff), + splt->contents + 4); + } + else + { + bfd_put_32 (output_bfd, plt_entry[0], splt->contents + 0); + bfd_put_32 (output_bfd, plt_entry[1], splt->contents + 4); + } + bfd_put_32 (output_bfd, plt_entry[2], splt->contents + 8); + bfd_put_32 (output_bfd, plt_entry[3], splt->contents + 12); + bfd_put_32 (output_bfd, plt_entry[4], splt->contents + 16); + bfd_put_32 (output_bfd, plt_entry[5], splt->contents + 20); + bfd_put_32 (output_bfd, plt_entry[6], splt->contents + 24); + bfd_put_32 (output_bfd, plt_entry[7], splt->contents + 28); + + if (! info->shared) + { + Elf_Internal_Rela rela; + bfd_byte *loc; + + loc = htab->srelplt2->contents; + + /* Output the @ha relocation for the first instruction. */ + rela.r_offset = (htab->plt->output_section->vma + + htab->plt->output_offset + + 2); + rela.r_info = ELF32_R_INFO (htab->hgot->indx, R_PPC_ADDR16_HA); + rela.r_addend = 0; + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + loc += sizeof (Elf32_External_Rela); + + /* Output the @l relocation for the second instruction. */ + rela.r_offset = (htab->plt->output_section->vma + + htab->plt->output_offset + + 6); + rela.r_info = ELF32_R_INFO (htab->hgot->indx, R_PPC_ADDR16_LO); + rela.r_addend = 0; + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + loc += sizeof (Elf32_External_Rela); + + /* Fix up the remaining relocations. They may have the wrong + symbol index for _G_O_T_ or _P_L_T_ depending on the order + in which symbols were output. */ + while (loc < htab->srelplt2->contents + htab->srelplt2->size) + { + Elf_Internal_Rela rel; + + bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); + rel.r_info = ELF32_R_INFO (htab->hgot->indx, R_PPC_ADDR16_HA); + bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); + loc += sizeof (Elf32_External_Rela); + + bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); + rel.r_info = ELF32_R_INFO (htab->hgot->indx, R_PPC_ADDR16_LO); + bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); + loc += sizeof (Elf32_External_Rela); + + bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); + rel.r_info = ELF32_R_INFO (htab->hplt->indx, R_PPC_ADDR32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); + loc += sizeof (Elf32_External_Rela); + } + } + } + if (htab->glink != NULL && htab->glink->contents != NULL) { unsigned char *p; @@ -6956,3 +7377,147 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd, #define elf_backend_plt_sym_val ppc_elf_plt_sym_val #include "elf32-target.h" + +/* VxWorks Target */ + +#undef TARGET_LITTLE_SYM +#undef TARGET_LITTLE_NAME + +#undef TARGET_BIG_SYM +#define TARGET_BIG_SYM bfd_elf32_powerpc_vxworks_vec +#undef TARGET_BIG_NAME +#define TARGET_BIG_NAME "elf32-powerpc-vxworks" + +/* This is the same as ppc_elf_special_sections except it does not include + the entry for .plt. */ +static struct bfd_elf_special_section const * + ppc_elf_vxworks_special_sections[27]= +{ + NULL, /* 'a' */ + NULL, /* 'b' */ + NULL, /* 'c' */ + NULL, /* 'd' */ + NULL, /* 'e' */ + NULL, /* 'f' */ + NULL, /* 'g' */ + NULL, /* 'h' */ + NULL, /* 'i' */ + NULL, /* 'j' */ + NULL, /* 'k' */ + NULL, /* 'l' */ + NULL, /* 'm' */ + NULL, /* 'n' */ + NULL, /* 'o' */ + NULL, /* 'p' */ + NULL, /* 'q' */ + NULL, /* 'r' */ + ppc_special_sections_s, /* 's' */ + ppc_special_sections_t, /* 's' */ + NULL, /* 'u' */ + NULL, /* 'v' */ + NULL, /* 'w' */ + NULL, /* 'x' */ + NULL, /* 'y' */ + NULL, /* 'z' */ + ppc_special_sections_other, /* other */ +}; + +/* Like ppc_elf_link_hash_table_create, but overrides + appropriately for VxWorks. */ +static struct bfd_link_hash_table * +ppc_elf_vxworks_link_hash_table_create (bfd *abfd) +{ + struct bfd_link_hash_table *ret; + + ret = ppc_elf_link_hash_table_create (abfd); + if (ret) + { + struct ppc_elf_link_hash_table *htab + = (struct ppc_elf_link_hash_table *)ret; + htab->is_vxworks = 1; + htab->plt_entry_size = VXWORKS_PLT_ENTRY_SIZE; + htab->plt_slot_size = VXWORKS_PLT_ENTRY_SIZE; + htab->plt_initial_entry_size = VXWORKS_PLT_INITIAL_ENTRY_SIZE; + } + return ret; +} + +/* Tweak magic VxWorks symbols as they are loaded. */ +static bfd_boolean +ppc_elf_vxworks_add_symbol_hook (bfd *abfd, + struct bfd_link_info *info, + Elf_Internal_Sym *sym, + const char **namep ATTRIBUTE_UNUSED, + flagword *flagsp ATTRIBUTE_UNUSED, + asection **secp, + bfd_vma *valp) +{ + if (!elf_vxworks_add_symbol_hook(abfd, info, sym,namep, flagsp, secp, + valp)) + return FALSE; + + return ppc_elf_add_symbol_hook(abfd, info, sym,namep, flagsp, secp, valp); +} + +/* Tweak magic VxWorks symbols as they are written to the output file. */ +static bfd_boolean +elf_i386_vxworks_link_output_symbol_hook (struct bfd_link_info *info + ATTRIBUTE_UNUSED, + const char *name, + Elf_Internal_Sym *sym, + asection *input_sec ATTRIBUTE_UNUSED, + struct elf_link_hash_entry *h + ATTRIBUTE_UNUSED) +{ + /* Ignore the first dummy symbol. */ + if (!name) + return TRUE; + + return elf_vxworks_link_output_symbol_hook (name, sym); +} + +static void +ppc_elf_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker) +{ + ppc_elf_final_write_processing(abfd, linker); + elf_vxworks_final_write_processing(abfd, linker); +} + +/* On VxWorks, we emit relocations against _PROCEDURE_LINKAGE_TABLE_, so + define it. */ +#undef elf_backend_want_plt_sym +#define elf_backend_want_plt_sym 1 +#undef elf_backend_want_got_plt +#define elf_backend_want_got_plt 1 +#undef elf_backend_got_symbol_offset +#define elf_backend_got_symbol_offset 0 +#undef elf_backend_plt_not_loaded +#define elf_backend_plt_not_loaded 0 +#undef elf_backend_plt_readonly +#define elf_backend_plt_readonly 1 +#undef elf_backend_got_header_size +#define elf_backend_got_header_size 12 + +#undef bfd_elf32_bfd_link_hash_table_create +#define bfd_elf32_bfd_link_hash_table_create \ + ppc_elf_vxworks_link_hash_table_create +#undef elf_backend_special_sections +#define elf_backend_special_sections \ + ppc_elf_vxworks_special_sections +#undef elf_backend_add_symbol_hook +#define elf_backend_add_symbol_hook \ + ppc_elf_vxworks_add_symbol_hook +#undef elf_backend_link_output_symbol_hook +#define elf_backend_link_output_symbol_hook \ + elf_i386_vxworks_link_output_symbol_hook +#undef elf_backend_final_write_processing +#define elf_backend_final_write_processing \ + ppc_elf_vxworks_final_write_processing +#undef elf_backend_emit_relocs +#define elf_backend_emit_relocs \ + elf_vxworks_emit_relocs + +#undef elf32_bed +#define elf32_bed ppc_elf_vxworks_bed + +#include "elf32-target.h" |