diff options
author | Paul Brook <paul@codesourcery.com> | 2005-05-05 14:37:15 +0000 |
---|---|---|
committer | Paul Brook <paul@codesourcery.com> | 2005-05-05 14:37:15 +0000 |
commit | c237ab4b5f02d2881b580ddea9d02f7fdf525d30 (patch) | |
tree | 6e22a04893103d9dd4f5de1c403c37045467d38c /bfd/elf32-i386.c | |
parent | ed85379194ed7ff9f7b28851025b5c5c0f0442a7 (diff) | |
download | gdb-c237ab4b5f02d2881b580ddea9d02f7fdf525d30.tar.gz |
2005-05-05 Paul Brook <paul@codesourcery.com>
bfd/
* config.bfd: Use bfd_elf32_i386_vxworks_vec for i?86-*-vxworks.
* configure.in: Add bfd_elf32_i386_vxworks_vec. i386 targets need
elf-vxworks.lo.
* configure: Regenerate.
* Makefile.am (BFD32_BACKENDS): Add elf-vxworks.lo.
(BFD32_BACKENDS_CFILES): Add elf-vxworks.c.
(elf32-i386.lo): Depend on elf-vxworks.h.
(elf-vxworks.lo): New rule.
* Makefile.in: Regenerate.
* elf-bfd.h (elf_backend_data): Update type of
elf_backend_emit_relocs.
(_bfd_elf_link_output_relocs): Update prototype.
* elflink.c (_bfd_elf_link_output_relocs): Always use
bed->elf_backend_emit_relocs when outputting relocations.
* elfxx-target.h (elf_backend_emit_relocs): Default to
_bfd_elf_link_output_relocs.
* targets.c (bfd_elf32_i386_vxworks_vec): Declare.
(_bfd_target_vector): Add bfd_elf32_i386_vxworks_vec.
* elf32-i386.c: Add elf32-i386-vxworks target BFD.
(elf_i386_plt0_entry): Remove padding.
(elf_i386_pic_plt0_entry): Ditto.
(PLTRESOLVE_RELOCS_SHLIB, PLTRESOLVE_RELOCS): Define.
(PLT_NON_JUMP_SLOT_RELOCS): Define.
(elf_i386_link_hash_table): Add srelplt2, hgot, hplt, is_vxworks and
plt0_pad_byte fields.
(elf_i386_link_hash_table_create): Zero them.
(elf_i386_create_dynamic_sections): Create static relocation section.
(allocate_dynrelocs): Allocate space for static PLT relocations.
(elf_i386_size_dynamic_sections): Save shortcuts to PLT and GOT
symbols. Give PLT symbols function type. Don't strip PLT sections
if we have exported symbols from them.
(elf_i386_finish_dynamic_symbol): Fill in VxWorks PLT static
relocation section. Don't mark _GLOBAL_OFFSET_TABLE_ as absolute on
VxWorks.
(elf_i386_finish_dynamic_sections): Allow different pad bytes.
Add relocation for GOT location. Fill in PLT static relocations.
(elf_i386_vxworks_link_hash_table_create): New function.
(elf_i386_vxworks_link_output_symbol_hook): New function.
* elf-vxworks.h: New file.
gas/
* config/tc-i386.h (ELF_TARGET_FORMAT): Define for TE_VXWORKS.
gas/testsuite/
* gas/i386/i386.exp: Don't run divide test on vxworks.
ld/
* Makefile.am: Add eelf_i386_vxworks.
* Makefile.in: Regenerate.
* configure.tgt: Make i?86-*-vxworks use targ_emul=elf_i386_vxworks.
* emulparams/elf_i386_vxworks.sh: New file.
* emulparams/vxworks.sh: New file.
* scripttempl/elf.sc: Add DATA_END_SYMBOLS and ETEXT_NAME.
Diffstat (limited to 'bfd/elf32-i386.c')
-rw-r--r-- | bfd/elf32-i386.c | 296 |
1 files changed, 280 insertions, 16 deletions
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 934e6d90fbd..35716796068 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -23,6 +23,7 @@ #include "bfdlink.h" #include "libbfd.h" #include "elf-bfd.h" +#include "elf-vxworks.h" /* 386 uses REL relocations instead of RELA. */ #define USE_REL 1 @@ -471,15 +472,15 @@ elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) #define PLT_ENTRY_SIZE 16 /* The first entry in an absolute procedure linkage table looks like - this. See the SVR4 ABI i386 supplement to see how this works. */ + this. See the SVR4 ABI i386 supplement to see how this works. + Will be padded to PLT_ENTRY_SIZE with htab->plt0_pad_byte. */ -static const bfd_byte elf_i386_plt0_entry[PLT_ENTRY_SIZE] = +static const bfd_byte elf_i386_plt0_entry[12] = { 0xff, 0x35, /* pushl contents of address */ 0, 0, 0, 0, /* replaced with address of .got + 4. */ 0xff, 0x25, /* jmp indirect */ - 0, 0, 0, 0, /* replaced with address of .got + 8. */ - 0, 0, 0, 0 /* pad out to 16 bytes. */ + 0, 0, 0, 0 /* replaced with address of .got + 8. */ }; /* Subsequent entries in an absolute procedure linkage table look like @@ -495,13 +496,13 @@ static const bfd_byte elf_i386_plt_entry[PLT_ENTRY_SIZE] = 0, 0, 0, 0 /* replaced with offset to start of .plt. */ }; -/* The first entry in a PIC procedure linkage table look like this. */ +/* The first entry in a PIC procedure linkage table look like this. + Will be padded to PLT_ENTRY_SIZE with htab->plt0_pad_byte. */ -static const bfd_byte elf_i386_pic_plt0_entry[PLT_ENTRY_SIZE] = +static const bfd_byte elf_i386_pic_plt0_entry[12] = { 0xff, 0xb3, 4, 0, 0, 0, /* pushl 4(%ebx) */ - 0xff, 0xa3, 8, 0, 0, 0, /* jmp *8(%ebx) */ - 0, 0, 0, 0 /* pad out to 16 bytes. */ + 0xff, 0xa3, 8, 0, 0, 0 /* jmp *8(%ebx) */ }; /* Subsequent entries in a PIC procedure linkage table look like this. */ @@ -516,6 +517,12 @@ static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] = 0, 0, 0, 0 /* replaced with offset to start of .plt. */ }; +/* On VxWorks, the .rel.plt.unloaded section has absolute relocations + for the PLTResolve stub and then for each PLT entry. */ +#define PLTRESOLVE_RELOCS_SHLIB 0 +#define PLTRESOLVE_RELOCS 2 +#define PLT_NON_JUMP_SLOT_RELOCS 2 + /* The i386 linker needs to keep track of the number of relocs that it decides to copy as dynamic relocs in check_relocs for each symbol. This is so that it can later discard them if they are found to be @@ -595,7 +602,19 @@ struct elf_i386_link_hash_table asection *srelplt; asection *sdynbss; asection *srelbss; + + /* The (unloaded but important) .rel.plt.unloaded section on VxWorks. */ + asection *srelplt2; + + /* Short-cuts to frequently used symbols for VxWorks targets. */ + struct elf_link_hash_entry *hgot, *hplt; + + /* True if the target system is VxWorks. */ + int is_vxworks; + /* Value used to fill the last word of the first plt entry. */ + bfd_byte plt0_pad_byte; + union { bfd_signed_vma refcount; bfd_vma offset; @@ -668,6 +687,11 @@ elf_i386_link_hash_table_create (bfd *abfd) ret->srelbss = NULL; ret->tls_ldm_got.refcount = 0; ret->sym_sec.abfd = NULL; + ret->is_vxworks = 0; + ret->srelplt2 = NULL; + ret->hgot = NULL; + ret->hplt = NULL; + ret->plt0_pad_byte = 0; return &ret->elf.root; } @@ -709,6 +733,9 @@ static bfd_boolean elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) { struct elf_i386_link_hash_table *htab; + asection * s; + int flags; + const struct elf_backend_data *bed = get_elf_backend_data (dynobj); htab = elf_i386_hash_table (info); if (!htab->sgot && !create_got_section (dynobj, info)) @@ -727,6 +754,18 @@ elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) || (!info->shared && !htab->srelbss)) abort (); + if (htab->is_vxworks && !info->shared) + { + s = bfd_make_section (dynobj, ".rel.plt.unloaded"); + flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_READONLY + | SEC_LINKER_CREATED); + if (s == NULL + || ! bfd_set_section_flags (dynobj, s, flags) + || ! bfd_set_section_alignment (dynobj, s, bed->s->log_file_align)) + return FALSE; + htab->srelplt2 = s; + } + return TRUE; } @@ -1528,6 +1567,26 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* We also need to make an entry in the .rel.plt section. */ htab->srelplt->size += sizeof (Elf32_External_Rel); + + if (htab->is_vxworks && !info->shared) + { + /* VxWorks has a second set of relocations for each PLT entry + in executables. They go in a separate relocation section, + which is processed by the kernel loader. */ + + /* There are two relocations for the initial PLT entry: an + R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 4 and an + R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 8. */ + + if (h->plt.offset == PLT_ENTRY_SIZE) + htab->srelplt2->size += (sizeof (Elf32_External_Rel) * 2); + + /* There are two extra relocations for each subsequent PLT entry: + an R_386_32 relocation for the GOT entry, and an R_386_32 + relocation for the PLT entry. */ + + htab->srelplt2->size += (sizeof (Elf32_External_Rel) * 2); + } } else { @@ -1818,6 +1877,27 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, else htab->tls_ldm_got.offset = -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 (htab->is_vxworks && htab->hplt && htab->splt->flags & SEC_CODE) + htab->hplt->type = STT_FUNC; + } + /* Allocate global sym .plt and .got entries, and space for global sym dynamic relocs. */ elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info); @@ -1827,6 +1907,8 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, relocs = FALSE; for (s = dynobj->sections; s != NULL; s = s->next) { + bfd_boolean strip_section = TRUE; + if ((s->flags & SEC_LINKER_CREATED) == 0) continue; @@ -1836,10 +1918,16 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, { /* Strip this section if we don't need it; see the comment below. */ + /* 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 (htab->hplt != NULL) + strip_section = FALSE; } else if (strncmp (bfd_get_section_name (dynobj, s), ".rel", 4) == 0) { - if (s->size != 0 && s != htab->srelplt) + if (s->size != 0 && s != htab->srelplt && s != htab->srelplt2) relocs = TRUE; /* We use the reloc_count field as a counter if we need @@ -1852,7 +1940,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, continue; } - if (s->size == 0) + if (s->size == 0 && strip_section) { /* If we don't need this section, strip it from the output file. This is mostly to handle .rel.bss and @@ -3031,6 +3119,43 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, + htab->sgotplt->output_offset + got_offset), htab->splt->contents + h->plt.offset + 2); + + if (htab->is_vxworks) + { + int s, k, reloc_index; + + /* Create the R_386_32 relocation referencing the GOT + for this PLT entry. */ + + /* S: Current slot number (zero-based). */ + s = (h->plt.offset - PLT_ENTRY_SIZE) / PLT_ENTRY_SIZE; + /* K: Number of relocations for PLTResolve. */ + if (info->shared) + k = PLTRESOLVE_RELOCS_SHLIB; + else + k = PLTRESOLVE_RELOCS; + /* Skip the PLTresolve relocations, and the relocations for + the other PLT slots. */ + reloc_index = k + s * PLT_NON_JUMP_SLOT_RELOCS; + loc = (htab->srelplt2->contents + reloc_index + * sizeof (Elf32_External_Rel)); + + rel.r_offset = (htab->splt->output_section->vma + + htab->splt->output_offset + + h->plt.offset + 2), + rel.r_info = ELF32_R_INFO (htab->hgot->indx, R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); + + /* Create the R_386_32 relocation referencing the beginning of + the PLT for this GOT entry. */ + rel.r_offset = (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + got_offset); + rel.r_info = ELF32_R_INFO (htab->hplt->indx, R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, + loc + sizeof (Elf32_External_Rel)); + } + } else { @@ -3140,9 +3265,12 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); } - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ + /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. + On VxWorks, the _GLOBAL_OFFSET_TABLE_ symbol is not absolute: it + is relative to the ".got" section. */ if (strcmp (h->root.root.string, "_DYNAMIC") == 0 - || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) + || (strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 + && !htab->is_vxworks)) sym->st_shndx = SHN_ABS; return TRUE; @@ -3250,12 +3378,20 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, if (htab->splt && htab->splt->size > 0) { if (info->shared) - memcpy (htab->splt->contents, - elf_i386_pic_plt0_entry, PLT_ENTRY_SIZE); + { + memcpy (htab->splt->contents, elf_i386_pic_plt0_entry, + sizeof (elf_i386_pic_plt0_entry)); + memset (htab->splt->contents + sizeof (elf_i386_pic_plt0_entry), + htab->plt0_pad_byte, + PLT_ENTRY_SIZE - sizeof (elf_i386_pic_plt0_entry)); + } else { - memcpy (htab->splt->contents, - elf_i386_plt0_entry, PLT_ENTRY_SIZE); + memcpy (htab->splt->contents, elf_i386_plt0_entry, + sizeof(elf_i386_plt0_entry)); + memset (htab->splt->contents + sizeof (elf_i386_plt0_entry), + htab->plt0_pad_byte, + PLT_ENTRY_SIZE - sizeof (elf_i386_plt0_entry)); bfd_put_32 (output_bfd, (htab->sgotplt->output_section->vma + htab->sgotplt->output_offset @@ -3266,12 +3402,69 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, + htab->sgotplt->output_offset + 8), htab->splt->contents + 8); + + if (htab->is_vxworks) + { + Elf_Internal_Rela rel; + struct elf_link_hash_entry *hgot; + + /* The VxWorks GOT is relocated by the dynamic linker. + Therefore, we must emit relocations rather than + simply computing the values now. */ + hgot = elf_link_hash_lookup (elf_hash_table (info), + "_GLOBAL_OFFSET_TABLE_", + FALSE, FALSE, FALSE); + /* Generate a relocation for _GLOBAL_OFFSET_TABLE_ + 4. + On IA32 we use REL relocations so the addend goes in + the PLT directly. */ + rel.r_offset = (htab->splt->output_section->vma + + htab->splt->output_offset + + 2); + rel.r_info = ELF32_R_INFO (hgot->indx, R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, + htab->srelplt2->contents); + /* Generate a relocation for _GLOBAL_OFFSET_TABLE_ + 8. */ + rel.r_offset = (htab->splt->output_section->vma + + htab->splt->output_offset + + 8); + rel.r_info = ELF32_R_INFO (hgot->indx, R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, + htab->srelplt2->contents + + sizeof (Elf32_External_Rel)); + } } /* UnixWare sets the entsize of .plt to 4, although that doesn't really seem like the right value. */ elf_section_data (htab->splt->output_section) ->this_hdr.sh_entsize = 4; + + /* Correct the .rel.plt.unloaded relocations. */ + if (htab->is_vxworks && !info->shared) + { + int num_plts = (htab->splt->size / PLT_ENTRY_SIZE) - 1; + char *p; + + p = htab->srelplt2->contents; + if (info->shared) + p += PLTRESOLVE_RELOCS_SHLIB * sizeof (Elf32_External_Rel); + else + p += PLTRESOLVE_RELOCS * sizeof (Elf32_External_Rel); + + for (; num_plts; num_plts--) + { + Elf_Internal_Rela rel; + bfd_elf32_swap_reloc_in (output_bfd, p, &rel); + rel.r_info = ELF32_R_INFO (htab->hgot->indx, R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, p); + p += sizeof (Elf32_External_Rel); + + bfd_elf32_swap_reloc_in (output_bfd, p, &rel); + rel.r_info = ELF32_R_INFO (htab->hplt->indx, R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, p); + p += sizeof (Elf32_External_Rel); + } + } } } @@ -3382,3 +3575,74 @@ elf_i386_post_process_headers (bfd *abfd, #define elf32_bed elf32_i386_fbsd_bed #include "elf32-target.h" + +/* VxWorks support. */ + +#undef TARGET_LITTLE_SYM +#define TARGET_LITTLE_SYM bfd_elf32_i386_vxworks_vec +#undef TARGET_LITTLE_NAME +#define TARGET_LITTLE_NAME "elf32-i386-vxworks" + + +/* Like elf_i386_link_hash_table_create but with tweaks for VxWorks. */ + +static struct bfd_link_hash_table * +elf_i386_vxworks_link_hash_table_create (bfd *abfd) +{ + struct bfd_link_hash_table *ret; + struct elf_i386_link_hash_table *htab; + + ret = elf_i386_link_hash_table_create (abfd); + if (ret) + { + htab = (struct elf_i386_link_hash_table *) ret; + htab->is_vxworks = 1; + htab->plt0_pad_byte = 0x90; + } + + return ret; +} + + +/* 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); +} + +#undef elf_backend_post_process_headers +#undef bfd_elf32_bfd_link_hash_table_create +#define bfd_elf32_bfd_link_hash_table_create \ + elf_i386_vxworks_link_hash_table_create +#undef elf_backend_add_symbol_hook +#define elf_backend_add_symbol_hook \ + 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_emit_relocs +#define elf_backend_emit_relocs elf_vxworks_emit_relocs +#undef elf_backend_final_write_processing +#define elf_backend_final_write_processing \ + elf_vxworks_final_write_processing + +/* 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 elf32_bed +#define elf32_bed elf32_i386_vxworks_bed + +#include "elf32-target.h" |