/* ELF executable support for BFD.
- Copyright 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
+ Copyright 1991, 92, 93, 94, 95, 96, 97, 98, 1999 Free Software
+ Foundation, Inc.
Written by Fred Fish @ Cygnus Support, from information published
in "UNIX System V Release 4, Programmers Guide: ANSI C and
#include "bfdlink.h"
#include "libbfd.h"
#include "elf-bfd.h"
-#include "fnmatch.h"
/* Renaming structures, typedefs, macros and functions to be size-specific. */
#define Elf_External_Ehdr NAME(Elf,External_Ehdr)
#define elf_bfd_final_link NAME(bfd_elf,bfd_final_link)
#define elf_create_pointer_linker_section NAME(bfd_elf,create_pointer_linker_section)
#define elf_finish_pointer_linker_section NAME(bfd_elf,finish_pointer_linker_section)
+#define elf_gc_sections NAME(_bfd_elf,gc_sections)
+#define elf_gc_common_finalize_got_offsets \
+ NAME(_bfd_elf,gc_common_finalize_got_offsets)
+#define elf_gc_common_final_link NAME(_bfd_elf,gc_common_final_link)
+#define elf_gc_record_vtinherit NAME(_bfd_elf,gc_record_vtinherit)
+#define elf_gc_record_vtentry NAME(_bfd_elf,gc_record_vtentry)
+#define elf_link_record_local_dynamic_symbol \
+ NAME(_bfd_elf,link_record_local_dynamic_symbol)
#if ARCH_SIZE == 64
#define ELF_R_INFO(X,Y) ELF64_R_INFO(X,Y)
#define LOG_FILE_ALIGN 2
#endif
-/* Forward declarations of static functions */
+/* Static functions */
static void elf_swap_ehdr_in
PARAMS ((bfd *, const Elf_External_Ehdr *, Elf_Internal_Ehdr *));
#define section_from_elf_index bfd_section_from_elf_index
+static boolean elf_slurp_reloc_table_from_section
+ PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, bfd_size_type,
+ arelent *, asymbol **, boolean));
static boolean elf_slurp_reloc_table
PARAMS ((bfd *, asection *, asymbol **, boolean));
static void write_relocs PARAMS ((bfd *, asection *, PTR));
+static boolean elf_file_p PARAMS ((Elf_External_Ehdr *));
+
#ifdef DEBUG
static void elf_debug_section PARAMS ((int, Elf_Internal_Shdr *));
static void elf_debug_file PARAMS ((Elf_Internal_Ehdr *));
can be handled by explicitly specifying 32 bits or "the long type". */
#if ARCH_SIZE == 64
#define put_word bfd_h_put_64
+#define put_signed_word bfd_h_put_signed_64
#define get_word bfd_h_get_64
+#define get_signed_word bfd_h_get_signed_64
#endif
#if ARCH_SIZE == 32
#define put_word bfd_h_put_32
+#define put_signed_word bfd_h_put_signed_32
#define get_word bfd_h_get_32
+#define get_signed_word bfd_h_get_signed_32
#endif
/* Translate an ELF symbol in external format into an ELF symbol in internal
const Elf_External_Sym *src;
Elf_Internal_Sym *dst;
{
+ int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma;
+
dst->st_name = bfd_h_get_32 (abfd, (bfd_byte *) src->st_name);
- dst->st_value = get_word (abfd, (bfd_byte *) src->st_value);
+ if (signed_vma)
+ dst->st_value = get_signed_word (abfd, (bfd_byte *) src->st_value);
+ else
+ dst->st_value = get_word (abfd, (bfd_byte *) src->st_value);
dst->st_size = get_word (abfd, (bfd_byte *) src->st_size);
dst->st_info = bfd_h_get_8 (abfd, (bfd_byte *) src->st_info);
dst->st_other = bfd_h_get_8 (abfd, (bfd_byte *) src->st_other);
const Elf_External_Shdr *src;
Elf_Internal_Shdr *dst;
{
+ int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma;
+
dst->sh_name = bfd_h_get_32 (abfd, (bfd_byte *) src->sh_name);
dst->sh_type = bfd_h_get_32 (abfd, (bfd_byte *) src->sh_type);
dst->sh_flags = get_word (abfd, (bfd_byte *) src->sh_flags);
- dst->sh_addr = get_word (abfd, (bfd_byte *) src->sh_addr);
+ if (signed_vma)
+ dst->sh_addr = get_signed_word (abfd, (bfd_byte *) src->sh_addr);
+ else
+ dst->sh_addr = get_word (abfd, (bfd_byte *) src->sh_addr);
dst->sh_offset = get_word (abfd, (bfd_byte *) src->sh_offset);
dst->sh_size = get_word (abfd, (bfd_byte *) src->sh_size);
dst->sh_link = bfd_h_get_32 (abfd, (bfd_byte *) src->sh_link);
const Elf_External_Phdr *src;
Elf_Internal_Phdr *dst;
{
+ int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma;
+
dst->p_type = bfd_h_get_32 (abfd, (bfd_byte *) src->p_type);
dst->p_flags = bfd_h_get_32 (abfd, (bfd_byte *) src->p_flags);
dst->p_offset = get_word (abfd, (bfd_byte *) src->p_offset);
- dst->p_vaddr = get_word (abfd, (bfd_byte *) src->p_vaddr);
- dst->p_paddr = get_word (abfd, (bfd_byte *) src->p_paddr);
+ if (signed_vma)
+ {
+ dst->p_vaddr = get_signed_word (abfd, (bfd_byte *) src->p_vaddr);
+ dst->p_paddr = get_signed_word (abfd, (bfd_byte *) src->p_paddr);
+ }
+ else
+ {
+ dst->p_vaddr = get_word (abfd, (bfd_byte *) src->p_vaddr);
+ dst->p_paddr = get_word (abfd, (bfd_byte *) src->p_paddr);
+ }
dst->p_filesz = get_word (abfd, (bfd_byte *) src->p_filesz);
dst->p_memsz = get_word (abfd, (bfd_byte *) src->p_memsz);
dst->p_align = get_word (abfd, (bfd_byte *) src->p_align);
{
dst->r_offset = get_word (abfd, (bfd_byte *) src->r_offset);
dst->r_info = get_word (abfd, (bfd_byte *) src->r_info);
- dst->r_addend = get_word (abfd, (bfd_byte *) src->r_addend);
+ dst->r_addend = get_signed_word (abfd, (bfd_byte *) src->r_addend);
}
/* Translate an ELF reloc from internal format to external format. */
{
put_word (abfd, src->r_offset, dst->r_offset);
put_word (abfd, src->r_info, dst->r_info);
- put_word (abfd, src->r_addend, dst->r_addend);
+ put_signed_word (abfd, src->r_addend, dst->r_addend);
}
INLINE void
}
INLINE void
-elf_swap_dyn_out (abfd, src, dst)
+elf_swap_dyn_out (abfd, src, p)
bfd *abfd;
const Elf_Internal_Dyn *src;
- Elf_External_Dyn *dst;
+ PTR p;
{
+ Elf_External_Dyn *dst = (Elf_External_Dyn *) p;
+
put_word (abfd, src->d_tag, dst->d_tag);
put_word (abfd, src->d_un.d_val, dst->d_un.d_val);
}
elf_debug_file (i_ehdrp);
#endif
+ /* Reject ET_CORE (header indicates core file, not object file) */
+ if (i_ehdrp->e_type == ET_CORE)
+ goto got_wrong_format_error;
+
/* If there is no section header table, we're hosed. */
if (i_ehdrp->e_shoff == 0)
goto got_wrong_format_error;
abfd->flags |= D_PAGED;
if (! bfd_default_set_arch_mach (abfd, ebd->arch, 0))
- goto got_no_match;
+ {
+ /* It's OK if this fails for the generic target. */
+ if (ebd->elf_machine_code != EM_NONE)
+ goto got_no_match;
+ }
/* Remember the entry point specified in the ELF file header. */
bfd_get_start_address (abfd) = i_ehdrp->e_entry;
return (abfd->xvec);
-got_wrong_format_error:
+ got_wrong_format_error:
bfd_set_error (bfd_error_wrong_format);
- goto got_no_match;
-got_no_match:
+ got_no_match:
if (new_tdata != NULL
&& new_tdata->elf_sect_ptr != NULL)
bfd_release (abfd, new_tdata->elf_sect_ptr);
Elf_External_Rela *outbound_relocas;
Elf_External_Rel *outbound_relocs;
unsigned int idx;
- int use_rela_p = get_elf_backend_data (abfd)->use_rela_p;
+ int use_rela_p;
asymbol *last_sym = 0;
int last_sym_idx = 0;
return;
}
+ /* Figure out whether the relocations are RELA or REL relocations. */
+ if (rela_hdr->sh_type == SHT_RELA)
+ use_rela_p = true;
+ else if (rela_hdr->sh_type == SHT_REL)
+ use_rela_p = false;
+ else
+ /* Every relocation section should be either an SHT_RELA or an
+ SHT_REL section. */
+ abort ();
+
/* orelocation has the data, reloc_count has the count... */
if (use_rela_p)
{
if (sym == last_sym)
n = last_sym_idx;
+ else if (bfd_is_abs_section (sym->section) && sym->value == 0)
+ n = STN_UNDEF;
else
{
last_sym = sym;
last_sym_idx = n;
}
- if ((*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec
+ if ((*ptr->sym_ptr_ptr)->the_bfd != NULL
+ && (*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec
&& ! _bfd_elf_validate_reloc (abfd, ptr))
{
*failedp = true;
{
Elf_Internal_Shdr *hdr;
Elf_Internal_Shdr *verhdr;
- long symcount; /* Number of external ELF symbols */
+ unsigned long symcount; /* Number of external ELF symbols */
elf_symbol_type *sym; /* Pointer to current bfd symbol */
elf_symbol_type *symbase; /* Buffer for generated bfd symbols */
Elf_Internal_Sym i_sym;
else
{
hdr = &elf_tdata (abfd)->dynsymtab_hdr;
- verhdr = &elf_tdata (abfd)->dynversym_hdr;
+ if (elf_dynversym (abfd) == 0)
+ verhdr = NULL;
+ else
+ verhdr = &elf_tdata (abfd)->dynversym_hdr;
if ((elf_tdata (abfd)->dynverdef_section != 0
&& elf_tdata (abfd)->verdef == NULL)
|| (elf_tdata (abfd)->dynverref_section != 0
sym = symbase = NULL;
else
{
- long i;
+ unsigned long i;
if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) == -1)
return -1;
/* Read the raw ELF version symbol information. */
- if (elf_dynversym (abfd) != 0
- && verhdr != NULL
+ if (verhdr != NULL
&& verhdr->sh_size / sizeof (Elf_External_Versym) != symcount)
{
(*_bfd_error_handler)
- ("%s: version count (%ld) does not match symbol count (%ld)",
+ (_("%s: version count (%ld) does not match symbol count (%ld)"),
abfd->filename,
(long) (verhdr->sh_size / sizeof (Elf_External_Versym)),
symcount);
goto error_return;
x_versymp = (Elf_External_Versym *) bfd_malloc (verhdr->sh_size);
- if (x_versymp == NULL && symcount != 0)
+ if (x_versymp == NULL && verhdr->sh_size != 0)
goto error_return;
if (bfd_read ((PTR) x_versymp, 1, verhdr->sh_size, abfd)
else
sym->symbol.section = bfd_abs_section_ptr;
- sym->symbol.value -= sym->symbol.section->vma;
+ /* If this is a relocateable file, then the symbol value is
+ already section relative. */
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
+ sym->symbol.value -= sym->symbol.section->vma;
switch (ELF_ST_BIND (i_sym.st_info))
{
return -1;
}
-/* Read in and swap the external relocs. */
+/* Read relocations for ASECT from REL_HDR. There are RELOC_COUNT of
+ them. */
static boolean
-elf_slurp_reloc_table (abfd, asect, symbols, dynamic)
+elf_slurp_reloc_table_from_section (abfd, asect, rel_hdr, reloc_count,
+ relents, symbols, dynamic)
bfd *abfd;
asection *asect;
+ Elf_Internal_Shdr *rel_hdr;
+ bfd_size_type reloc_count;
+ arelent *relents;
asymbol **symbols;
boolean dynamic;
{
struct elf_backend_data * const ebd = get_elf_backend_data (abfd);
- struct bfd_elf_section_data * const d = elf_section_data (asect);
- Elf_Internal_Shdr *rel_hdr;
- bfd_size_type reloc_count;
PTR allocated = NULL;
bfd_byte *native_relocs;
- arelent *relents;
arelent *relent;
unsigned int i;
int entsize;
- if (asect->relocation != NULL)
- return true;
-
- if (! dynamic)
- {
- if ((asect->flags & SEC_RELOC) == 0
- || asect->reloc_count == 0)
- return true;
-
- rel_hdr = &d->rel_hdr;
- reloc_count = asect->reloc_count;
-
- BFD_ASSERT (asect->rel_filepos == rel_hdr->sh_offset
- && reloc_count == rel_hdr->sh_size / rel_hdr->sh_entsize);
- }
- else
- {
- if (asect->_raw_size == 0)
- return true;
-
- rel_hdr = &d->this_hdr;
- reloc_count = rel_hdr->sh_size / rel_hdr->sh_entsize;
- }
-
allocated = (PTR) bfd_malloc ((size_t) rel_hdr->sh_size);
if (allocated == NULL)
goto error_return;
native_relocs = (bfd_byte *) allocated;
- relents = (arelent *) bfd_alloc (abfd, reloc_count * sizeof (arelent));
- if (relents == NULL)
- goto error_return;
-
entsize = rel_hdr->sh_entsize;
BFD_ASSERT (entsize == sizeof (Elf_External_Rel)
|| entsize == sizeof (Elf_External_Rela));
(*ebd->elf_info_to_howto_rel) (abfd, relent, &rel);
}
- asect->relocation = relents;
-
if (allocated != NULL)
free (allocated);
return false;
}
+/* Read in and swap the external relocs. */
+
+static boolean
+elf_slurp_reloc_table (abfd, asect, symbols, dynamic)
+ bfd *abfd;
+ asection *asect;
+ asymbol **symbols;
+ boolean dynamic;
+{
+ struct bfd_elf_section_data * const d = elf_section_data (asect);
+ Elf_Internal_Shdr *rel_hdr;
+ Elf_Internal_Shdr *rel_hdr2;
+ bfd_size_type reloc_count;
+ bfd_size_type reloc_count2;
+ arelent *relents;
+
+ if (asect->relocation != NULL)
+ return true;
+
+ if (! dynamic)
+ {
+ if ((asect->flags & SEC_RELOC) == 0
+ || asect->reloc_count == 0)
+ return true;
+
+ rel_hdr = &d->rel_hdr;
+ reloc_count = rel_hdr->sh_size / rel_hdr->sh_entsize;
+ rel_hdr2 = d->rel_hdr2;
+ reloc_count2 = (rel_hdr2
+ ? (rel_hdr2->sh_size / rel_hdr2->sh_entsize)
+ : 0);
+
+ BFD_ASSERT (asect->reloc_count == reloc_count + reloc_count2);
+ BFD_ASSERT (asect->rel_filepos == rel_hdr->sh_offset
+ || (rel_hdr2 && asect->rel_filepos == rel_hdr2->sh_offset));
+
+ }
+ else
+ {
+ /* Note that ASECT->RELOC_COUNT tends not to be accurate in this
+ case because relocations against this section may use the
+ dynamic symbol table, and in that case bfd_section_from_shdr
+ in elf.c does not update the RELOC_COUNT. */
+ if (asect->_raw_size == 0)
+ return true;
+
+ rel_hdr = &d->this_hdr;
+ reloc_count = rel_hdr->sh_size / rel_hdr->sh_entsize;
+ rel_hdr2 = NULL;
+ reloc_count2 = 0;
+ }
+
+ relents = ((arelent *)
+ bfd_alloc (abfd,
+ (reloc_count + reloc_count2) * sizeof (arelent)));
+ if (relents == NULL)
+ return false;
+
+ if (!elf_slurp_reloc_table_from_section (abfd, asect,
+ rel_hdr, reloc_count,
+ relents,
+ symbols, dynamic))
+ return false;
+
+ if (rel_hdr2
+ && !elf_slurp_reloc_table_from_section (abfd, asect,
+ rel_hdr2, reloc_count2,
+ relents + reloc_count,
+ symbols, dynamic))
+ return false;
+
+
+ asect->relocation = relents;
+ return true;
+}
+
#ifdef DEBUG
static void
elf_debug_section (num, hdr)
sizeof (Elf_External_Sym),
sizeof (Elf_External_Dyn),
sizeof (Elf_External_Note),
-
+ ARCH_SIZE / 8,
+ 1,
ARCH_SIZE, FILE_ALIGN,
ELFCLASS, EV_CURRENT,
elf_write_out_phdrs,
elf_swap_symbol_out,
elf_slurp_reloc_table,
elf_slurp_symbol_table,
- elf_swap_dyn_in
+ elf_swap_dyn_in,
+ elf_swap_dyn_out,
+ NULL,
+ NULL,
+ NULL,
+ NULL
};