/* ELF executable support for BFD.
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
/* For sparc64-cross-sparc32. */
#define _SYSCALL32
-#include "bfd.h"
#include "sysdep.h"
+#include "bfd.h"
#include "bfdlink.h"
#include "libbfd.h"
#define ARCH_SIZE 0
return h & 0xffffffff;
}
+/* DT_GNU_HASH hash function. Do not change this function; you will
+ cause invalid hash tables to be generated. */
+
+unsigned long
+bfd_elf_gnu_hash (const char *namearg)
+{
+ const unsigned char *name = (const unsigned char *) namearg;
+ unsigned long h = 5381;
+ unsigned char ch;
+
+ while ((ch = *name++) != '\0')
+ h = (h << 5) + h + ch;
+ return h & 0xffffffff;
+}
+
bfd_boolean
bfd_elf_mkobject (bfd *abfd)
{
- /* This just does initialization. */
- /* coff_mkobject zalloc's space for tdata.coff_obj_data ... */
- elf_tdata (abfd) = bfd_zalloc (abfd, sizeof (struct elf_obj_tdata));
- if (elf_tdata (abfd) == 0)
- return FALSE;
- /* Since everything is done at close time, do we need any
- initialization? */
+ if (abfd->tdata.any == NULL)
+ {
+ abfd->tdata.any = bfd_zalloc (abfd, sizeof (struct elf_obj_tdata));
+ if (abfd->tdata.any == NULL)
+ return FALSE;
+ }
+
+ elf_tdata (abfd)->program_header_size = (bfd_size_type) -1;
return TRUE;
}
bfd_size_type shstrtabsize;
i_shdrp = elf_elfsections (abfd);
- if (i_shdrp == 0 || i_shdrp[shindex] == 0)
+ if (i_shdrp == 0
+ || shindex >= elf_numsections (abfd)
+ || i_shdrp[shindex] == 0)
return NULL;
shstrtab = i_shdrp[shindex]->contents;
if (strindex == 0)
return "";
+ if (elf_elfsections (abfd) == NULL || shindex >= elf_numsections (abfd))
+ return NULL;
+
hdr = elf_elfsections (abfd)[shindex];
if (hdr->contents == NULL
for (esym = extsym_buf, isym = intsym_buf, shndx = extshndx_buf;
isym < isymend;
esym += extsym_size, isym++, shndx = shndx != NULL ? shndx + 1 : NULL)
- (*bed->s->swap_symbol_in) (ibfd, esym, shndx, isym);
+ if (!(*bed->s->swap_symbol_in) (ibfd, esym, shndx, isym))
+ {
+ symoffset += (esym - (bfd_byte *) extsym_buf) / extsym_size;
+ (*_bfd_error_handler) (_("%B symbol number %lu references "
+ "nonexistent SHT_SYMTAB_SHNDX section"),
+ ibfd, (unsigned long) symoffset);
+ intsym_buf = NULL;
+ goto out;
+ }
out:
if (alloc_ext != NULL)
section with just a flag word (ie. sh_size is 4), ignore it. */
shnum = elf_numsections (abfd);
num_group = 0;
+
+#define IS_VALID_GROUP_SECTION_HEADER(shdr) \
+ ( (shdr)->sh_type == SHT_GROUP \
+ && (shdr)->sh_size >= (2 * GRP_ENTRY_SIZE) \
+ && (shdr)->sh_entsize == GRP_ENTRY_SIZE \
+ && ((shdr)->sh_size % GRP_ENTRY_SIZE) == 0)
+
for (i = 0; i < shnum; i++)
{
Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
- if (shdr->sh_type == SHT_GROUP && shdr->sh_size >= 8)
+
+ if (IS_VALID_GROUP_SECTION_HEADER (shdr))
num_group += 1;
}
for (i = 0; i < shnum; i++)
{
Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i];
- if (shdr->sh_type == SHT_GROUP && shdr->sh_size >= 8)
+
+ if (IS_VALID_GROUP_SECTION_HEADER (shdr))
{
unsigned char *src;
Elf_Internal_Group *dest;
amt = shdr->sh_size * sizeof (*dest) / 4;
shdr->contents = bfd_alloc2 (abfd, shdr->sh_size,
sizeof (*dest) / 4);
- if (shdr->contents == NULL
- || bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0
+ /* PR binutils/4110: Handle corrupt group headers. */
+ if (shdr->contents == NULL)
+ {
+ _bfd_error_handler
+ (_("%B: Corrupt size field in group section header: 0x%lx"), abfd, shdr->sh_size);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ memset (shdr->contents, 0, amt);
+
+ if (bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0
|| (bfd_bread (shdr->contents, shdr->sh_size, abfd)
!= shdr->sh_size))
return FALSE;
int len;
} debug_sections [] =
{
- { "debug", 5 }, /* 'd' */
+ { STRING_COMMA_LEN ("debug") }, /* 'd' */
{ NULL, 0 }, /* 'e' */
{ NULL, 0 }, /* 'f' */
- { "gnu.linkonce.wi.", 17 }, /* 'g' */
+ { STRING_COMMA_LEN ("gnu.linkonce.wi.") }, /* 'g' */
{ NULL, 0 }, /* 'h' */
{ NULL, 0 }, /* 'i' */
{ NULL, 0 }, /* 'j' */
{ NULL, 0 }, /* 'k' */
- { "line", 4 }, /* 'l' */
+ { STRING_COMMA_LEN ("line") }, /* 'l' */
{ NULL, 0 }, /* 'm' */
{ NULL, 0 }, /* 'n' */
{ NULL, 0 }, /* 'o' */
{ NULL, 0 }, /* 'p' */
{ NULL, 0 }, /* 'q' */
{ NULL, 0 }, /* 'r' */
- { "stab", 4 } /* 's' */
+ { STRING_COMMA_LEN ("stab") } /* 's' */
};
if (name [0] == '.')
The symbols will be defined as weak, so that multiple definitions
are permitted. The GNU linker extension is to actually discard
all but one of the sections. */
- if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0
+ if (CONST_STRNEQ (name, ".gnu.linkonce")
&& elf_next_in_group (newsect) == NULL)
flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
case DT_AUXILIARY: name = "AUXILIARY"; stringp = TRUE; break;
case DT_USED: name = "USED"; break;
case DT_FILTER: name = "FILTER"; stringp = TRUE; break;
+ case DT_GNU_HASH: name = "GNU_HASH"; break;
}
fprintf (f, " %-11s ", name);
bfd_boolean ret;
int can_refcount = get_elf_backend_data (abfd)->can_refcount;
- table->dynamic_sections_created = FALSE;
- table->dynobj = NULL;
+ memset (table, 0, sizeof * table);
table->init_got_refcount.refcount = can_refcount - 1;
table->init_plt_refcount.refcount = can_refcount - 1;
table->init_got_offset.offset = -(bfd_vma) 1;
table->init_plt_offset.offset = -(bfd_vma) 1;
/* The first dynamic symbol is a dummy. */
table->dynsymcount = 1;
- table->dynstr = NULL;
- table->bucketcount = 0;
- table->needed = NULL;
- table->hgot = NULL;
- table->merge_info = NULL;
- memset (&table->stab_info, 0, sizeof (table->stab_info));
- memset (&table->eh_info, 0, sizeof (table->eh_info));
- table->dynlocal = NULL;
- table->runpath = NULL;
- table->tls_sec = NULL;
- table->tls_size = 0;
- table->loaded = NULL;
- table->is_relocatable_executable = FALSE;
ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize);
table->root.type = bfd_link_elf_hash_table;
}
void
-bfd_elf_set_dyn_lib_class (bfd *abfd, int lib_class)
+bfd_elf_set_dyn_lib_class (bfd *abfd, enum dynamic_lib_link_class lib_class)
{
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
&& bfd_get_format (abfd) == bfd_object)
case SHT_FINI_ARRAY: /* .fini_array section. */
case SHT_PREINIT_ARRAY: /* .preinit_array section. */
case SHT_GNU_LIBLIST: /* .gnu.liblist section. */
+ case SHT_GNU_HASH: /* .gnu.hash section. */
return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
case SHT_DYNAMIC: /* Dynamic linking information. */
abfd->flags |= HAS_RELOC;
return TRUE;
}
- break;
case SHT_GNU_verdef:
elf_dynverdef (abfd) = shindex;
elf_tdata (abfd)->dynverdef_hdr = *hdr;
return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
- break;
case SHT_GNU_versym:
if (hdr->sh_entsize != sizeof (Elf_External_Versym))
/* We need a BFD section for objcopy and relocatable linking,
and it's handy to have the signature available as the section
name. */
- if (hdr->sh_entsize != GRP_ENTRY_SIZE)
+ if (! IS_VALID_GROUP_SECTION_HEADER (hdr))
return FALSE;
name = group_signature (abfd, hdr);
if (name == NULL)
if (hdr->contents != NULL)
{
Elf_Internal_Group *idx = (Elf_Internal_Group *) hdr->contents;
- unsigned int n_elt = hdr->sh_size / 4;
+ unsigned int n_elt = hdr->sh_size / GRP_ENTRY_SIZE;
asection *s;
if (idx->flags & GRP_COMDAT)
/* We try to keep the same section order as it comes in. */
idx += n_elt;
while (--n_elt != 0)
- if ((s = (--idx)->shdr->bfd_section) != NULL
- && elf_next_in_group (s) != NULL)
- {
- elf_next_in_group (hdr->bfd_section) = s;
- break;
- }
+ {
+ --idx;
+
+ if (idx->shdr != NULL
+ && (s = idx->shdr->bfd_section) != NULL
+ && elf_next_in_group (s) != NULL)
+ {
+ elf_next_in_group (hdr->bfd_section) = s;
+ break;
+ }
+ }
}
break;
"`%s' [0x%8x]"),
abfd, name, hdr->sh_type);
else if (hdr->sh_type >= SHT_LOOS && hdr->sh_type <= SHT_HIOS)
- /* FIXME: We should handle this section. */
- (*_bfd_error_handler)
- (_("%B: don't know how to handle OS specific section "
- "`%s' [0x%8x]"),
- abfd, name, hdr->sh_type);
+ {
+ /* Unrecognised OS-specific sections. */
+ if ((hdr->sh_flags & SHF_OS_NONCONFORMING) != 0)
+ /* SHF_OS_NONCONFORMING indicates that special knowledge is
+ required to correctly process the section and the file should
+ be rejected with an error message. */
+ (*_bfd_error_handler)
+ (_("%B: don't know how to handle OS specific section "
+ "`%s' [0x%8x]"),
+ abfd, name, hdr->sh_type);
+ else
+ /* Otherwise it should be processed. */
+ return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+ }
else
/* FIXME: We should handle this section. */
(*_bfd_error_handler)
static const struct bfd_elf_special_section special_sections_b[] =
{
- { ".bss", 4, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
- { NULL, 0, 0, 0, 0 }
+ { STRING_COMMA_LEN (".bss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
+ { NULL, 0, 0, 0, 0 }
};
static const struct bfd_elf_special_section special_sections_c[] =
{
- { ".comment", 8, 0, SHT_PROGBITS, 0 },
- { NULL, 0, 0, 0, 0 }
+ { STRING_COMMA_LEN (".comment"), 0, SHT_PROGBITS, 0 },
+ { NULL, 0, 0, 0, 0 }
};
static const struct bfd_elf_special_section special_sections_d[] =
{
- { ".data", 5, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
- { ".data1", 6, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
- { ".debug", 6, 0, SHT_PROGBITS, 0 },
- { ".debug_line", 11, 0, SHT_PROGBITS, 0 },
- { ".debug_info", 11, 0, SHT_PROGBITS, 0 },
- { ".debug_abbrev", 13, 0, SHT_PROGBITS, 0 },
- { ".debug_aranges", 14, 0, SHT_PROGBITS, 0 },
- { ".dynamic", 8, 0, SHT_DYNAMIC, SHF_ALLOC },
- { ".dynstr", 7, 0, SHT_STRTAB, SHF_ALLOC },
- { ".dynsym", 7, 0, SHT_DYNSYM, SHF_ALLOC },
- { NULL, 0, 0, 0, 0 }
+ { STRING_COMMA_LEN (".data"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".data1"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".debug"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".debug_line"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".debug_info"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".debug_abbrev"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".debug_aranges"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".dynamic"), 0, SHT_DYNAMIC, SHF_ALLOC },
+ { STRING_COMMA_LEN (".dynstr"), 0, SHT_STRTAB, SHF_ALLOC },
+ { STRING_COMMA_LEN (".dynsym"), 0, SHT_DYNSYM, SHF_ALLOC },
+ { NULL, 0, 0, 0, 0 }
};
static const struct bfd_elf_special_section special_sections_f[] =
{
- { ".fini", 5, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
- { ".fini_array", 11, 0, SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE },
- { NULL, 0, 0, 0, 0 }
+ { STRING_COMMA_LEN (".fini"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { STRING_COMMA_LEN (".fini_array"), 0, SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE },
+ { NULL, 0, 0, 0, 0 }
};
static const struct bfd_elf_special_section special_sections_g[] =
{
- { ".gnu.linkonce.b",15, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
- { ".got", 4, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
- { ".gnu.version", 12, 0, SHT_GNU_versym, 0 },
- { ".gnu.version_d", 14, 0, SHT_GNU_verdef, 0 },
- { ".gnu.version_r", 14, 0, SHT_GNU_verneed, 0 },
- { ".gnu.liblist", 12, 0, SHT_GNU_LIBLIST, SHF_ALLOC },
- { ".gnu.conflict", 13, 0, SHT_RELA, SHF_ALLOC },
- { NULL, 0, 0, 0, 0 }
+ { STRING_COMMA_LEN (".gnu.linkonce.b"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".got"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".gnu.version"), 0, SHT_GNU_versym, 0 },
+ { STRING_COMMA_LEN (".gnu.version_d"), 0, SHT_GNU_verdef, 0 },
+ { STRING_COMMA_LEN (".gnu.version_r"), 0, SHT_GNU_verneed, 0 },
+ { STRING_COMMA_LEN (".gnu.liblist"), 0, SHT_GNU_LIBLIST, SHF_ALLOC },
+ { STRING_COMMA_LEN (".gnu.conflict"), 0, SHT_RELA, SHF_ALLOC },
+ { STRING_COMMA_LEN (".gnu.hash"), 0, SHT_GNU_HASH, SHF_ALLOC },
+ { NULL, 0, 0, 0, 0 }
};
static const struct bfd_elf_special_section special_sections_h[] =
{
- { ".hash", 5, 0, SHT_HASH, SHF_ALLOC },
- { NULL, 0, 0, 0, 0 }
+ { STRING_COMMA_LEN (".hash"), 0, SHT_HASH, SHF_ALLOC },
+ { NULL, 0, 0, 0, 0 }
};
static const struct bfd_elf_special_section special_sections_i[] =
{
- { ".init", 5, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
- { ".init_array", 11, 0, SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE },
- { ".interp", 7, 0, SHT_PROGBITS, 0 },
- { NULL, 0, 0, 0, 0 }
+ { STRING_COMMA_LEN (".init"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { STRING_COMMA_LEN (".init_array"), 0, SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".interp"), 0, SHT_PROGBITS, 0 },
+ { NULL, 0, 0, 0, 0 }
};
static const struct bfd_elf_special_section special_sections_l[] =
{
- { ".line", 5, 0, SHT_PROGBITS, 0 },
- { NULL, 0, 0, 0, 0 }
+ { STRING_COMMA_LEN (".line"), 0, SHT_PROGBITS, 0 },
+ { NULL, 0, 0, 0, 0 }
};
static const struct bfd_elf_special_section special_sections_n[] =
{
- { ".note.GNU-stack",15, 0, SHT_PROGBITS, 0 },
- { ".note", 5, -1, SHT_NOTE, 0 },
- { NULL, 0, 0, 0, 0 }
+ { STRING_COMMA_LEN (".note.GNU-stack"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".note"), -1, SHT_NOTE, 0 },
+ { NULL, 0, 0, 0, 0 }
};
static const struct bfd_elf_special_section special_sections_p[] =
{
- { ".preinit_array", 14, 0, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE },
- { ".plt", 4, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
- { NULL, 0, 0, 0, 0 }
+ { STRING_COMMA_LEN (".preinit_array"), 0, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE },
+ { STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { NULL, 0, 0, 0, 0 }
};
static const struct bfd_elf_special_section special_sections_r[] =
{
- { ".rodata", 7, -2, SHT_PROGBITS, SHF_ALLOC },
- { ".rodata1", 8, 0, SHT_PROGBITS, SHF_ALLOC },
- { ".rela", 5, -1, SHT_RELA, 0 },
- { ".rel", 4, -1, SHT_REL, 0 },
- { NULL, 0, 0, 0, 0 }
+ { STRING_COMMA_LEN (".rodata"), -2, SHT_PROGBITS, SHF_ALLOC },
+ { STRING_COMMA_LEN (".rodata1"), 0, SHT_PROGBITS, SHF_ALLOC },
+ { STRING_COMMA_LEN (".rela"), -1, SHT_RELA, 0 },
+ { STRING_COMMA_LEN (".rel"), -1, SHT_REL, 0 },
+ { NULL, 0, 0, 0, 0 }
};
static const struct bfd_elf_special_section special_sections_s[] =
{
- { ".shstrtab", 9, 0, SHT_STRTAB, 0 },
- { ".strtab", 7, 0, SHT_STRTAB, 0 },
- { ".symtab", 7, 0, SHT_SYMTAB, 0 },
- { ".stabstr", 5, 3, SHT_STRTAB, 0 },
- { NULL, 0, 0, 0, 0 }
+ { STRING_COMMA_LEN (".shstrtab"), 0, SHT_STRTAB, 0 },
+ { STRING_COMMA_LEN (".strtab"), 0, SHT_STRTAB, 0 },
+ { STRING_COMMA_LEN (".symtab"), 0, SHT_SYMTAB, 0 },
+ /* See struct bfd_elf_special_section declaration for the semantics of
+ this special case where .prefix_length != strlen (.prefix). */
+ { ".stabstr", 5, 3, SHT_STRTAB, 0 },
+ { NULL, 0, 0, 0, 0 }
};
static const struct bfd_elf_special_section special_sections_t[] =
{
- { ".text", 5, -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
- { ".tbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS },
- { ".tdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS },
- { NULL, 0, 0, 0, 0 }
+ { STRING_COMMA_LEN (".text"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { STRING_COMMA_LEN (".tbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS },
+ { STRING_COMMA_LEN (".tdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS },
+ { NULL, 0, 0, 0, 0 }
};
static const struct bfd_elf_special_section *special_sections[] =
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
bfd_boolean *failedptr = failedptrarg;
Elf_Internal_Shdr *this_hdr;
+ unsigned int sh_type;
if (*failedptr)
{
break;
case SHT_GROUP:
- this_hdr->sh_entsize = 4;
+ this_hdr->sh_entsize = GRP_ENTRY_SIZE;
+ break;
+
+ case SHT_GNU_HASH:
+ this_hdr->sh_entsize = bed->s->arch_size == 64 ? 0 : 4;
break;
}
}
/* Check for processor-specific section types. */
+ sh_type = this_hdr->sh_type;
if (bed->elf_backend_fake_sections
&& !(*bed->elf_backend_fake_sections) (abfd, this_hdr, asect))
*failedptr = TRUE;
+ if (sh_type == SHT_NOBITS && asect->size != 0)
+ {
+ /* Don't change the header type from NOBITS if we are being
+ called for objcopy --only-keep-debug. */
+ this_hdr->sh_type = sh_type;
+ }
+
/* If the section has relocs, set up a section header for the
SHT_REL[A] section. If two relocation sections are required for
this section, it is up to the processor-specific back-end to
s, s->owner);
/* Point to the kept section if it has the same
size as the discarded one. */
- kept = _bfd_elf_check_kept_section (s);
+ kept = _bfd_elf_check_kept_section (s, link_info);
if (kept == NULL)
{
bfd_set_error (bfd_error_bad_value);
string section. We look for a section with the same name
but without the trailing ``str'', and set its sh_link
field to point to this section. */
- if (strncmp (sec->name, ".stab", sizeof ".stab" - 1) == 0
+ if (CONST_STRNEQ (sec->name, ".stab")
&& strcmp (sec->name + strlen (sec->name) - 3, "str") == 0)
{
size_t len;
break;
case SHT_HASH:
+ case SHT_GNU_HASH:
case SHT_GNU_versym:
/* sh_link is the section header index of the symbol table
this hash table or version table is for. */
return TRUE;
}
+/* Make an initial estimate of the size of the program header. If we
+ get the number wrong here, we'll redo section placement. */
+
+static bfd_size_type
+get_program_header_size (bfd *abfd, struct bfd_link_info *info)
+{
+ size_t segs;
+ asection *s;
+ const struct elf_backend_data *bed;
+
+ /* Assume we will need exactly two PT_LOAD segments: one for text
+ and one for data. */
+ segs = 2;
+
+ s = bfd_get_section_by_name (abfd, ".interp");
+ if (s != NULL && (s->flags & SEC_LOAD) != 0)
+ {
+ /* If we have a loadable interpreter section, we need a
+ PT_INTERP segment. In this case, assume we also need a
+ PT_PHDR segment, although that may not be true for all
+ targets. */
+ segs += 2;
+ }
+
+ if (bfd_get_section_by_name (abfd, ".dynamic") != NULL)
+ {
+ /* We need a PT_DYNAMIC segment. */
+ ++segs;
+
+ if (elf_tdata (abfd)->relro)
+ {
+ /* We need a PT_GNU_RELRO segment only when there is a
+ PT_DYNAMIC segment. */
+ ++segs;
+ }
+ }
+
+ if (elf_tdata (abfd)->eh_frame_hdr)
+ {
+ /* We need a PT_GNU_EH_FRAME segment. */
+ ++segs;
+ }
+
+ if (elf_tdata (abfd)->stack_flags)
+ {
+ /* We need a PT_GNU_STACK segment. */
+ ++segs;
+ }
+
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if ((s->flags & SEC_LOAD) != 0
+ && CONST_STRNEQ (s->name, ".note"))
+ {
+ /* We need a PT_NOTE segment. */
+ ++segs;
+ }
+ }
+
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if (s->flags & SEC_THREAD_LOCAL)
+ {
+ /* We need a PT_TLS segment. */
+ ++segs;
+ break;
+ }
+ }
+
+ /* Let the backend count up any program headers it might need. */
+ bed = get_elf_backend_data (abfd);
+ if (bed->elf_backend_additional_program_headers)
+ {
+ int a;
+
+ a = (*bed->elf_backend_additional_program_headers) (abfd, info);
+ if (a == -1)
+ abort ();
+ segs += a;
+ }
+
+ return segs * bed->s->sizeof_phdr;
+}
+
/* Create a mapping from a set of sections to a program segment. */
static struct elf_segment_map *
return m;
}
-/* Set up a mapping from BFD sections to program segments. */
+/* Possibly add or remove segments from the segment map. */
static bfd_boolean
-map_sections_to_segments (bfd *abfd)
+elf_modify_segment_map (bfd *abfd, struct bfd_link_info *info)
{
- asection **sections = NULL;
- asection *s;
- unsigned int i;
- unsigned int count;
- struct elf_segment_map *mfirst;
- struct elf_segment_map **pm;
- struct elf_segment_map *m;
- asection *last_hdr;
- bfd_vma last_size;
- unsigned int phdr_index;
- bfd_vma maxpagesize;
- asection **hdrpp;
- bfd_boolean phdr_in_segment = TRUE;
- bfd_boolean writable;
- int tls_count = 0;
- asection *first_tls = NULL;
- asection *dynsec, *eh_frame_hdr;
- bfd_size_type amt;
-
- if (elf_tdata (abfd)->segment_map != NULL)
- return TRUE;
+ struct elf_segment_map **m;
+ const struct elf_backend_data *bed;
- if (bfd_count_sections (abfd) == 0)
- return TRUE;
+ /* The placement algorithm assumes that non allocated sections are
+ not in PT_LOAD segments. We ensure this here by removing such
+ sections from the segment map. We also remove excluded
+ sections. Finally, any PT_LOAD segment without sections is
+ removed. */
+ m = &elf_tdata (abfd)->segment_map;
+ while (*m)
+ {
+ unsigned int i, new_count;
- /* Select the allocated sections, and sort them. */
+ for (new_count = 0, i = 0; i < (*m)->count; i++)
+ {
+ if (((*m)->sections[i]->flags & SEC_EXCLUDE) == 0
+ && (((*m)->sections[i]->flags & SEC_ALLOC) != 0
+ || (*m)->p_type != PT_LOAD))
+ {
+ (*m)->sections[new_count] = (*m)->sections[i];
+ new_count++;
+ }
+ }
+ (*m)->count = new_count;
- sections = bfd_malloc2 (bfd_count_sections (abfd), sizeof (asection *));
- if (sections == NULL)
- goto error_return;
+ if ((*m)->p_type == PT_LOAD && (*m)->count == 0)
+ *m = (*m)->next;
+ else
+ m = &(*m)->next;
+ }
- i = 0;
- for (s = abfd->sections; s != NULL; s = s->next)
+ bed = get_elf_backend_data (abfd);
+ if (bed->elf_backend_modify_segment_map != NULL)
{
- if ((s->flags & SEC_ALLOC) != 0)
- {
- sections[i] = s;
- ++i;
- }
+ if (!(*bed->elf_backend_modify_segment_map) (abfd, info))
+ return FALSE;
}
- BFD_ASSERT (i <= bfd_count_sections (abfd));
- count = i;
- qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections);
+ return TRUE;
+}
- /* Build the mapping. */
+/* Set up a mapping from BFD sections to program segments. */
- mfirst = NULL;
- pm = &mfirst;
+bfd_boolean
+_bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
+{
+ unsigned int count;
+ struct elf_segment_map *m;
+ asection **sections = NULL;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
- /* If we have a .interp section, then create a PT_PHDR segment for
- the program headers and a PT_INTERP segment for the .interp
- section. */
- s = bfd_get_section_by_name (abfd, ".interp");
- if (s != NULL && (s->flags & SEC_LOAD) != 0)
+ if (elf_tdata (abfd)->segment_map == NULL
+ && bfd_count_sections (abfd) != 0)
{
- amt = sizeof (struct elf_segment_map);
- m = bfd_zalloc (abfd, amt);
- if (m == NULL)
- goto error_return;
- m->next = NULL;
- m->p_type = PT_PHDR;
- /* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not. */
- m->p_flags = PF_R | PF_X;
- m->p_flags_valid = 1;
- m->includes_phdrs = 1;
+ asection *s;
+ unsigned int i;
+ struct elf_segment_map *mfirst;
+ struct elf_segment_map **pm;
+ asection *last_hdr;
+ bfd_vma last_size;
+ unsigned int phdr_index;
+ bfd_vma maxpagesize;
+ asection **hdrpp;
+ bfd_boolean phdr_in_segment = TRUE;
+ bfd_boolean writable;
+ int tls_count = 0;
+ asection *first_tls = NULL;
+ asection *dynsec, *eh_frame_hdr;
+ bfd_size_type amt;
- *pm = m;
- pm = &m->next;
+ /* Select the allocated sections, and sort them. */
- amt = sizeof (struct elf_segment_map);
- m = bfd_zalloc (abfd, amt);
- if (m == NULL)
+ sections = bfd_malloc2 (bfd_count_sections (abfd), sizeof (asection *));
+ if (sections == NULL)
goto error_return;
- m->next = NULL;
- m->p_type = PT_INTERP;
- m->count = 1;
- m->sections[0] = s;
-
- *pm = m;
- pm = &m->next;
- }
-
- /* Look through the sections. We put sections in the same program
- segment when the start of the second section can be placed within
- a few bytes of the end of the first section. */
- last_hdr = NULL;
- last_size = 0;
- phdr_index = 0;
- maxpagesize = get_elf_backend_data (abfd)->maxpagesize;
- writable = FALSE;
- dynsec = bfd_get_section_by_name (abfd, ".dynamic");
- if (dynsec != NULL
- && (dynsec->flags & SEC_LOAD) == 0)
- dynsec = NULL;
-
- /* Deal with -Ttext or something similar such that the first section
- is not adjacent to the program headers. This is an
- approximation, since at this point we don't know exactly how many
- program headers we will need. */
- if (count > 0)
- {
- bfd_size_type phdr_size;
-
- phdr_size = elf_tdata (abfd)->program_header_size;
- if (phdr_size == 0)
- phdr_size = get_elf_backend_data (abfd)->s->sizeof_phdr;
- if ((abfd->flags & D_PAGED) == 0
- || sections[0]->lma < phdr_size
- || sections[0]->lma % maxpagesize < phdr_size % maxpagesize)
- phdr_in_segment = FALSE;
- }
-
- for (i = 0, hdrpp = sections; i < count; i++, hdrpp++)
- {
- asection *hdr;
- bfd_boolean new_segment;
-
- hdr = *hdrpp;
-
- /* See if this section and the last one will fit in the same
- segment. */
- if (last_hdr == NULL)
- {
- /* If we don't have a segment yet, then we don't need a new
- one (we build the last one after this loop). */
- new_segment = FALSE;
- }
- else if (last_hdr->lma - last_hdr->vma != hdr->lma - hdr->vma)
+ i = 0;
+ for (s = abfd->sections; s != NULL; s = s->next)
{
- /* If this section has a different relation between the
- virtual address and the load address, then we need a new
- segment. */
- new_segment = TRUE;
- }
- else if (BFD_ALIGN (last_hdr->lma + last_size, maxpagesize)
- < BFD_ALIGN (hdr->lma, maxpagesize))
- {
- /* If putting this section in this segment would force us to
- skip a page in the segment, then we need a new segment. */
- new_segment = TRUE;
- }
- else if ((last_hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0
- && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0)
- {
- /* We don't want to put a loadable section after a
- nonloadable section in the same segment.
- Consider .tbss sections as loadable for this purpose. */
- new_segment = TRUE;
- }
- else if ((abfd->flags & D_PAGED) == 0)
- {
- /* If the file is not demand paged, which means that we
- don't require the sections to be correctly aligned in the
- file, then there is no other reason for a new segment. */
- new_segment = FALSE;
+ if ((s->flags & SEC_ALLOC) != 0)
+ {
+ sections[i] = s;
+ ++i;
+ }
}
- else if (! writable
- && (hdr->flags & SEC_READONLY) == 0
- && (((last_hdr->lma + last_size - 1)
- & ~(maxpagesize - 1))
- != (hdr->lma & ~(maxpagesize - 1))))
+ BFD_ASSERT (i <= bfd_count_sections (abfd));
+ count = i;
+
+ qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections);
+
+ /* Build the mapping. */
+
+ mfirst = NULL;
+ pm = &mfirst;
+
+ /* If we have a .interp section, then create a PT_PHDR segment for
+ the program headers and a PT_INTERP segment for the .interp
+ section. */
+ s = bfd_get_section_by_name (abfd, ".interp");
+ if (s != NULL && (s->flags & SEC_LOAD) != 0)
{
- /* We don't want to put a writable section in a read only
- segment, unless they are on the same page in memory
- anyhow. We already know that the last section does not
- bring us past the current section on the page, so the
- only case in which the new section is not on the same
- page as the previous section is when the previous section
- ends precisely on a page boundary. */
- new_segment = TRUE;
+ amt = sizeof (struct elf_segment_map);
+ m = bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_PHDR;
+ /* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not. */
+ m->p_flags = PF_R | PF_X;
+ m->p_flags_valid = 1;
+ m->includes_phdrs = 1;
+
+ *pm = m;
+ pm = &m->next;
+
+ amt = sizeof (struct elf_segment_map);
+ m = bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_INTERP;
+ m->count = 1;
+ m->sections[0] = s;
+
+ *pm = m;
+ pm = &m->next;
}
- else
+
+ /* Look through the sections. We put sections in the same program
+ segment when the start of the second section can be placed within
+ a few bytes of the end of the first section. */
+ last_hdr = NULL;
+ last_size = 0;
+ phdr_index = 0;
+ maxpagesize = bed->maxpagesize;
+ writable = FALSE;
+ dynsec = bfd_get_section_by_name (abfd, ".dynamic");
+ if (dynsec != NULL
+ && (dynsec->flags & SEC_LOAD) == 0)
+ dynsec = NULL;
+
+ /* Deal with -Ttext or something similar such that the first section
+ is not adjacent to the program headers. This is an
+ approximation, since at this point we don't know exactly how many
+ program headers we will need. */
+ if (count > 0)
{
- /* Otherwise, we can use the same segment. */
- new_segment = FALSE;
+ bfd_size_type phdr_size = elf_tdata (abfd)->program_header_size;
+
+ if (phdr_size == (bfd_size_type) -1)
+ phdr_size = get_program_header_size (abfd, info);
+ if ((abfd->flags & D_PAGED) == 0
+ || sections[0]->lma < phdr_size
+ || sections[0]->lma % maxpagesize < phdr_size % maxpagesize)
+ phdr_in_segment = FALSE;
}
- if (! new_segment)
+ for (i = 0, hdrpp = sections; i < count; i++, hdrpp++)
{
+ asection *hdr;
+ bfd_boolean new_segment;
+
+ hdr = *hdrpp;
+
+ /* See if this section and the last one will fit in the same
+ segment. */
+
+ if (last_hdr == NULL)
+ {
+ /* If we don't have a segment yet, then we don't need a new
+ one (we build the last one after this loop). */
+ new_segment = FALSE;
+ }
+ else if (last_hdr->lma - last_hdr->vma != hdr->lma - hdr->vma)
+ {
+ /* If this section has a different relation between the
+ virtual address and the load address, then we need a new
+ segment. */
+ new_segment = TRUE;
+ }
+ else if (BFD_ALIGN (last_hdr->lma + last_size, maxpagesize)
+ < BFD_ALIGN (hdr->lma, maxpagesize))
+ {
+ /* If putting this section in this segment would force us to
+ skip a page in the segment, then we need a new segment. */
+ new_segment = TRUE;
+ }
+ else if ((last_hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0
+ && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0)
+ {
+ /* We don't want to put a loadable section after a
+ nonloadable section in the same segment.
+ Consider .tbss sections as loadable for this purpose. */
+ new_segment = TRUE;
+ }
+ else if ((abfd->flags & D_PAGED) == 0)
+ {
+ /* If the file is not demand paged, which means that we
+ don't require the sections to be correctly aligned in the
+ file, then there is no other reason for a new segment. */
+ new_segment = FALSE;
+ }
+ else if (! writable
+ && (hdr->flags & SEC_READONLY) == 0
+ && (((last_hdr->lma + last_size - 1)
+ & ~(maxpagesize - 1))
+ != (hdr->lma & ~(maxpagesize - 1))))
+ {
+ /* We don't want to put a writable section in a read only
+ segment, unless they are on the same page in memory
+ anyhow. We already know that the last section does not
+ bring us past the current section on the page, so the
+ only case in which the new section is not on the same
+ page as the previous section is when the previous section
+ ends precisely on a page boundary. */
+ new_segment = TRUE;
+ }
+ else
+ {
+ /* Otherwise, we can use the same segment. */
+ new_segment = FALSE;
+ }
+
+ /* Allow interested parties a chance to override our decision. */
+ if (last_hdr && info->callbacks->override_segment_assignment)
+ new_segment = info->callbacks->override_segment_assignment (info, abfd, hdr, last_hdr, new_segment);
+
+ if (! new_segment)
+ {
+ if ((hdr->flags & SEC_READONLY) == 0)
+ writable = TRUE;
+ last_hdr = hdr;
+ /* .tbss sections effectively have zero size. */
+ if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD))
+ != SEC_THREAD_LOCAL)
+ last_size = hdr->size;
+ else
+ last_size = 0;
+ continue;
+ }
+
+ /* We need a new program segment. We must create a new program
+ header holding all the sections from phdr_index until hdr. */
+
+ m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
+ if (m == NULL)
+ goto error_return;
+
+ *pm = m;
+ pm = &m->next;
+
if ((hdr->flags & SEC_READONLY) == 0)
writable = TRUE;
+ else
+ writable = FALSE;
+
last_hdr = hdr;
/* .tbss sections effectively have zero size. */
if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL)
last_size = hdr->size;
else
last_size = 0;
- continue;
+ phdr_index = i;
+ phdr_in_segment = FALSE;
}
- /* We need a new program segment. We must create a new program
- header holding all the sections from phdr_index until hdr. */
+ /* Create a final PT_LOAD program segment. */
+ if (last_hdr != NULL)
+ {
+ m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
+ if (m == NULL)
+ goto error_return;
- m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
- if (m == NULL)
- goto error_return;
+ *pm = m;
+ pm = &m->next;
+ }
- *pm = m;
- pm = &m->next;
+ /* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */
+ if (dynsec != NULL)
+ {
+ m = _bfd_elf_make_dynamic_segment (abfd, dynsec);
+ if (m == NULL)
+ goto error_return;
+ *pm = m;
+ pm = &m->next;
+ }
- if ((hdr->flags & SEC_READONLY) == 0)
- writable = TRUE;
- else
- writable = FALSE;
+ /* For each loadable .note section, add a PT_NOTE segment. We don't
+ use bfd_get_section_by_name, because if we link together
+ nonloadable .note sections and loadable .note sections, we will
+ generate two .note sections in the output file. FIXME: Using
+ names for section types is bogus anyhow. */
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ if ((s->flags & SEC_LOAD) != 0
+ && CONST_STRNEQ (s->name, ".note"))
+ {
+ amt = sizeof (struct elf_segment_map);
+ m = bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_NOTE;
+ m->count = 1;
+ m->sections[0] = s;
- last_hdr = hdr;
- /* .tbss sections effectively have zero size. */
- if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL)
- last_size = hdr->size;
- else
- last_size = 0;
- phdr_index = i;
- phdr_in_segment = FALSE;
- }
+ *pm = m;
+ pm = &m->next;
+ }
+ if (s->flags & SEC_THREAD_LOCAL)
+ {
+ if (! tls_count)
+ first_tls = s;
+ tls_count++;
+ }
+ }
- /* Create a final PT_LOAD program segment. */
- if (last_hdr != NULL)
- {
- m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment);
- if (m == NULL)
- goto error_return;
+ /* If there are any SHF_TLS output sections, add PT_TLS segment. */
+ if (tls_count > 0)
+ {
+ int i;
- *pm = m;
- pm = &m->next;
- }
+ amt = sizeof (struct elf_segment_map);
+ amt += (tls_count - 1) * sizeof (asection *);
+ m = bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_TLS;
+ m->count = tls_count;
+ /* Mandated PF_R. */
+ m->p_flags = PF_R;
+ m->p_flags_valid = 1;
+ for (i = 0; i < tls_count; ++i)
+ {
+ BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL);
+ m->sections[i] = first_tls;
+ first_tls = first_tls->next;
+ }
- /* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */
- if (dynsec != NULL)
- {
- m = _bfd_elf_make_dynamic_segment (abfd, dynsec);
- if (m == NULL)
- goto error_return;
- *pm = m;
- pm = &m->next;
- }
+ *pm = m;
+ pm = &m->next;
+ }
- /* For each loadable .note section, add a PT_NOTE segment. We don't
- use bfd_get_section_by_name, because if we link together
- nonloadable .note sections and loadable .note sections, we will
- generate two .note sections in the output file. FIXME: Using
- names for section types is bogus anyhow. */
- for (s = abfd->sections; s != NULL; s = s->next)
- {
- if ((s->flags & SEC_LOAD) != 0
- && strncmp (s->name, ".note", 5) == 0)
+ /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME
+ segment. */
+ eh_frame_hdr = elf_tdata (abfd)->eh_frame_hdr;
+ if (eh_frame_hdr != NULL
+ && (eh_frame_hdr->output_section->flags & SEC_LOAD) != 0)
{
amt = sizeof (struct elf_segment_map);
m = bfd_zalloc (abfd, amt);
if (m == NULL)
goto error_return;
m->next = NULL;
- m->p_type = PT_NOTE;
+ m->p_type = PT_GNU_EH_FRAME;
m->count = 1;
- m->sections[0] = s;
+ m->sections[0] = eh_frame_hdr->output_section;
*pm = m;
pm = &m->next;
}
- if (s->flags & SEC_THREAD_LOCAL)
- {
- if (! tls_count)
- first_tls = s;
- tls_count++;
- }
- }
- /* If there are any SHF_TLS output sections, add PT_TLS segment. */
- if (tls_count > 0)
- {
- int i;
-
- amt = sizeof (struct elf_segment_map);
- amt += (tls_count - 1) * sizeof (asection *);
- m = bfd_zalloc (abfd, amt);
- if (m == NULL)
- goto error_return;
- m->next = NULL;
- m->p_type = PT_TLS;
- m->count = tls_count;
- /* Mandated PF_R. */
- m->p_flags = PF_R;
- m->p_flags_valid = 1;
- for (i = 0; i < tls_count; ++i)
+ if (elf_tdata (abfd)->stack_flags)
{
- BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL);
- m->sections[i] = first_tls;
- first_tls = first_tls->next;
- }
-
- *pm = m;
- pm = &m->next;
- }
+ amt = sizeof (struct elf_segment_map);
+ m = bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_GNU_STACK;
+ m->p_flags = elf_tdata (abfd)->stack_flags;
+ m->p_flags_valid = 1;
- /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME
- segment. */
- eh_frame_hdr = elf_tdata (abfd)->eh_frame_hdr;
- if (eh_frame_hdr != NULL
- && (eh_frame_hdr->output_section->flags & SEC_LOAD) != 0)
- {
- amt = sizeof (struct elf_segment_map);
- m = bfd_zalloc (abfd, amt);
- if (m == NULL)
- goto error_return;
- m->next = NULL;
- m->p_type = PT_GNU_EH_FRAME;
- m->count = 1;
- m->sections[0] = eh_frame_hdr->output_section;
+ *pm = m;
+ pm = &m->next;
+ }
- *pm = m;
- pm = &m->next;
- }
+ if (dynsec != NULL && elf_tdata (abfd)->relro)
+ {
+ /* We make a PT_GNU_RELRO segment only when there is a
+ PT_DYNAMIC segment. */
+ amt = sizeof (struct elf_segment_map);
+ m = bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_GNU_RELRO;
+ m->p_flags = PF_R;
+ m->p_flags_valid = 1;
- if (elf_tdata (abfd)->stack_flags)
- {
- amt = sizeof (struct elf_segment_map);
- m = bfd_zalloc (abfd, amt);
- if (m == NULL)
- goto error_return;
- m->next = NULL;
- m->p_type = PT_GNU_STACK;
- m->p_flags = elf_tdata (abfd)->stack_flags;
- m->p_flags_valid = 1;
+ *pm = m;
+ pm = &m->next;
+ }
- *pm = m;
- pm = &m->next;
+ free (sections);
+ elf_tdata (abfd)->segment_map = mfirst;
}
- if (elf_tdata (abfd)->relro)
- {
- amt = sizeof (struct elf_segment_map);
- m = bfd_zalloc (abfd, amt);
- if (m == NULL)
- goto error_return;
- m->next = NULL;
- m->p_type = PT_GNU_RELRO;
- m->p_flags = PF_R;
- m->p_flags_valid = 1;
-
- *pm = m;
- pm = &m->next;
- }
+ if (!elf_modify_segment_map (abfd, info))
+ return FALSE;
- free (sections);
- sections = NULL;
+ for (count = 0, m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+ ++count;
+ elf_tdata (abfd)->program_header_size = count * bed->s->sizeof_phdr;
- elf_tdata (abfd)->segment_map = mfirst;
return TRUE;
error_return:
return ((vma - off) % maxpagesize);
}
-static void
-print_segment_map (bfd *abfd)
-{
- struct elf_segment_map *m;
- unsigned int i, j;
-
- fprintf (stderr, _(" Section to Segment mapping:\n"));
- fprintf (stderr, _(" Segment Sections...\n"));
-
- for (i= 0, m = elf_tdata (abfd)->segment_map;
- m != NULL;
- i++, m = m->next)
- {
- const char *pt = get_segment_type (m->p_type);
- char buf[32];
-
- if (pt == NULL)
- {
- if (m->p_type >= PT_LOPROC && m->p_type <= PT_HIPROC)
- sprintf (buf, "LOPROC+%7.7x",
- (unsigned int) (m->p_type - PT_LOPROC));
- else if (m->p_type >= PT_LOOS && m->p_type <= PT_HIOS)
- sprintf (buf, "LOOS+%7.7x",
- (unsigned int) (m->p_type - PT_LOOS));
- else
- snprintf (buf, sizeof (buf), "%8.8x",
- (unsigned int) m->p_type);
- pt = buf;
- }
- fprintf (stderr, " %2.2d: %14.14s: ", i, pt);
- for (j = 0; j < m->count; j++)
- fprintf (stderr, "%s ", m->sections [j]->name);
- putc ('\n',stderr);
- }
-}
-
/* Assign file positions to the sections based on the mapping from
sections to segments. This function also sets up some fields in
the file header. */
struct elf_segment_map *m;
Elf_Internal_Phdr *phdrs;
Elf_Internal_Phdr *p;
- file_ptr off, voff;
+ file_ptr off;
bfd_size_type maxpagesize;
- unsigned int count;
unsigned int alloc;
- unsigned int i;
-
- if (elf_tdata (abfd)->segment_map == NULL)
- {
- if (! map_sections_to_segments (abfd))
- return FALSE;
- }
- else
- {
- /* The placement algorithm assumes that non allocated sections are
- not in PT_LOAD segments. We ensure this here by removing such
- sections from the segment map. We also remove excluded
- sections. */
- for (m = elf_tdata (abfd)->segment_map;
- m != NULL;
- m = m->next)
- {
- unsigned int new_count;
-
- new_count = 0;
- for (i = 0; i < m->count; i ++)
- {
- if ((m->sections[i]->flags & SEC_EXCLUDE) == 0
- && ((m->sections[i]->flags & SEC_ALLOC) != 0
- || m->p_type != PT_LOAD))
- {
- if (i != new_count)
- m->sections[new_count] = m->sections[i];
-
- new_count ++;
- }
- }
-
- if (new_count != m->count)
- m->count = new_count;
- }
- }
+ unsigned int i, j;
- if (bed->elf_backend_modify_segment_map)
- {
- if (! (*bed->elf_backend_modify_segment_map) (abfd, link_info))
- return FALSE;
- }
+ if (link_info == NULL
+ && !elf_modify_segment_map (abfd, link_info))
+ return FALSE;
- count = 0;
+ alloc = 0;
for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
- ++count;
+ ++alloc;
elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr;
elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr;
- elf_elfheader (abfd)->e_phnum = count;
-
- if (count == 0)
- {
- elf_tdata (abfd)->next_file_pos = bed->s->sizeof_ehdr;
- return TRUE;
- }
+ elf_elfheader (abfd)->e_phnum = alloc;
- /* If we already counted the number of program segments, make sure
- that we allocated enough space. This happens when SIZEOF_HEADERS
- is used in a linker script. */
- alloc = elf_tdata (abfd)->program_header_size / bed->s->sizeof_phdr;
- if (alloc != 0 && count > alloc)
- {
- ((*_bfd_error_handler)
- (_("%B: Not enough room for program headers (allocated %u, need %u)"),
- abfd, alloc, count));
- print_segment_map (abfd);
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
+ if (elf_tdata (abfd)->program_header_size == (bfd_size_type) -1)
+ elf_tdata (abfd)->program_header_size = alloc * bed->s->sizeof_phdr;
+ else
+ BFD_ASSERT (elf_tdata (abfd)->program_header_size
+ >= alloc * bed->s->sizeof_phdr);
if (alloc == 0)
{
- alloc = count;
- elf_tdata (abfd)->program_header_size = alloc * bed->s->sizeof_phdr;
+ elf_tdata (abfd)->next_file_pos = bed->s->sizeof_ehdr;
+ return TRUE;
}
phdrs = bfd_alloc2 (abfd, alloc, sizeof (Elf_Internal_Phdr));
off = bed->s->sizeof_ehdr;
off += alloc * bed->s->sizeof_phdr;
- for (m = elf_tdata (abfd)->segment_map, p = phdrs;
+ for (m = elf_tdata (abfd)->segment_map, p = phdrs, j = 0;
m != NULL;
- m = m->next, p++)
+ m = m->next, p++, j++)
{
asection **secpp;
number of sections with contents contributing to both p_filesz
and p_memsz, followed by a number of sections with no contents
that just contribute to p_memsz. In this loop, OFF tracks next
- available file offset for PT_LOAD and PT_NOTE segments. VOFF is
- an adjustment we use for segments that have no file contents
- but need zero filled memory allocation. */
- voff = 0;
+ available file offset for PT_LOAD and PT_NOTE segments. */
p->p_type = m->p_type;
p->p_flags = m->p_flags;
if (m->count == 0)
p->p_vaddr = 0;
else
- p->p_vaddr = m->sections[0]->vma;
+ p->p_vaddr = m->sections[0]->vma - m->p_vaddr_offset;
if (m->p_paddr_valid)
p->p_paddr = m->p_paddr;
}
else if (m->count == 0)
p->p_align = 1 << bed->s->log_file_align;
+ else if (m->p_align_valid)
+ p->p_align = m->p_align;
else
p->p_align = 0;
bfd_vma adjust;
unsigned int align_power = 0;
- for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
+ if (m->p_align_valid)
+ align = p->p_align;
+ else
{
- unsigned int secalign;
-
- secalign = bfd_get_section_alignment (abfd, *secpp);
- if (secalign > align_power)
- align_power = secalign;
+ for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
+ {
+ unsigned int secalign;
+
+ secalign = bfd_get_section_alignment (abfd, *secpp);
+ if (secalign > align_power)
+ align_power = secalign;
+ }
+ align = (bfd_size_type) 1 << align_power;
+ if (align < maxpagesize)
+ align = maxpagesize;
}
- align = (bfd_size_type) 1 << align_power;
- if (align < maxpagesize)
- align = maxpagesize;
+ for (i = 0; i < m->count; i++)
+ if ((m->sections[i]->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+ /* If we aren't making room for this section, then
+ it must be SHT_NOBITS regardless of what we've
+ set via struct bfd_elf_special_section. */
+ elf_section_type (m->sections[i]) = SHT_NOBITS;
adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align);
- off += adjust;
- if (adjust != 0
- && !m->includes_filehdr
- && !m->includes_phdrs
- && (ufile_ptr) off >= align)
+ if (adjust != 0)
{
- /* If the first section isn't loadable, the same holds for
- any other sections. Since the segment won't need file
- space, we can make p_offset overlap some prior segment.
- However, .tbss is special. If a segment starts with
- .tbss, we need to look at the next section to decide
- whether the segment has any loadable sections. */
+ /* If the first section isn't loadable, the same holds
+ for any other sections. We don't need to align the
+ segment on disk since the segment doesn't need file
+ space. */
i = 0;
- while ((m->sections[i]->flags & SEC_LOAD) == 0)
+ while (elf_section_type (m->sections[i]) == SHT_NOBITS)
{
- if ((m->sections[i]->flags & SEC_THREAD_LOCAL) == 0
+ /* If a segment starts with .tbss, we need to look
+ at the next section to decide whether the segment
+ has any loadable sections. */
+ if ((elf_section_flags (m->sections[i]) & SHF_TLS) == 0
|| ++i >= m->count)
{
- off -= adjust;
- voff = adjust - align;
+ adjust = 0;
break;
}
}
+ off += adjust;
}
}
/* Make sure the .dynamic section is the first section in the
{
if (! m->p_flags_valid)
p->p_flags |= PF_R;
- p->p_offset = 0;
p->p_filesz = bed->s->sizeof_ehdr;
p->p_memsz = bed->s->sizeof_ehdr;
if (m->count > 0)
|| (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core))
{
if (! m->includes_filehdr && ! m->includes_phdrs)
- p->p_offset = off + voff;
+ p->p_offset = off;
else
{
file_ptr adjust;
for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
{
asection *sec;
- flagword flags;
bfd_size_type align;
+ Elf_Internal_Shdr *this_hdr;
sec = *secpp;
- flags = sec->flags;
+ this_hdr = &elf_section_data (sec)->this_hdr;
align = (bfd_size_type) 1 << bfd_get_section_alignment (abfd, sec);
if (p->p_type == PT_LOAD
|| p->p_type == PT_TLS)
{
- bfd_signed_vma adjust;
+ bfd_signed_vma adjust = sec->lma - (p->p_paddr + p->p_memsz);
- if ((flags & SEC_LOAD) != 0)
+ if (this_hdr->sh_type != SHT_NOBITS
+ || ((this_hdr->sh_flags & SHF_ALLOC) != 0
+ && ((this_hdr->sh_flags & SHF_TLS) == 0
+ || p->p_type == PT_TLS)))
{
- adjust = sec->lma - (p->p_paddr + p->p_filesz);
if (adjust < 0)
{
(*_bfd_error_handler)
abfd, sec, (unsigned long) sec->lma);
adjust = 0;
}
- off += adjust;
- p->p_filesz += adjust;
- p->p_memsz += adjust;
- }
- /* .tbss is special. It doesn't contribute to p_memsz of
- normal segments. */
- else if ((flags & SEC_ALLOC) != 0
- && ((flags & SEC_THREAD_LOCAL) == 0
- || p->p_type == PT_TLS))
- {
- /* The section VMA must equal the file position
- modulo the page size. */
- bfd_size_type page = align;
- if (page < maxpagesize)
- page = maxpagesize;
- adjust = vma_page_aligned_bias (sec->vma,
- p->p_vaddr + p->p_memsz,
- page);
p->p_memsz += adjust;
+
+ if (this_hdr->sh_type != SHT_NOBITS)
+ {
+ off += adjust;
+ p->p_filesz += adjust;
+ }
}
}
everything. */
if (i == 0)
{
- sec->filepos = off;
+ this_hdr->sh_offset = sec->filepos = off;
off += sec->size;
p->p_filesz = sec->size;
p->p_memsz = 0;
{
if (p->p_type == PT_LOAD)
{
- sec->filepos = off;
- /* FIXME: The SEC_HAS_CONTENTS test here dates back to
- 1997, and the exact reason for it isn't clear. One
- plausible explanation is that it is to work around
- a problem we have with linker scripts using data
- statements in NOLOAD sections. I don't think it
- makes a great deal of sense to have such a section
- assigned to a PT_LOAD segment, but apparently
- people do this. The data statement results in a
- bfd_data_link_order being built, and these need
- section contents to write into. Eventually, we get
- to _bfd_elf_write_object_contents which writes any
- section with contents to the output. Make room
- here for the write, so that following segments are
- not trashed. */
- if ((flags & SEC_LOAD) != 0
- || (flags & SEC_HAS_CONTENTS) != 0)
+ this_hdr->sh_offset = sec->filepos = off;
+ if (this_hdr->sh_type != SHT_NOBITS)
off += sec->size;
}
- if ((flags & SEC_LOAD) != 0)
+ if (this_hdr->sh_type != SHT_NOBITS)
{
p->p_filesz += sec->size;
- p->p_memsz += sec->size;
+ /* A load section without SHF_ALLOC is something like
+ a note section in a PT_NOTE segment. These take
+ file space but are not loaded into memory. */
+ if ((this_hdr->sh_flags & SHF_ALLOC) != 0)
+ p->p_memsz += sec->size;
}
/* .tbss is special. It doesn't contribute to p_memsz of
normal segments. */
- else if ((flags & SEC_ALLOC) != 0
- && ((flags & SEC_THREAD_LOCAL) == 0
+ else if ((this_hdr->sh_flags & SHF_ALLOC) != 0
+ && ((this_hdr->sh_flags & SHF_TLS) == 0
|| p->p_type == PT_TLS))
p->p_memsz += sec->size;
p->p_memsz += o->offset + o->size;
}
- if (align > p->p_align
- && (p->p_type != PT_LOAD
- || (abfd->flags & D_PAGED) == 0))
+ if (p->p_type == PT_GNU_RELRO)
+ p->p_align = 1;
+ else if (align > p->p_align
+ && !m->p_align_valid
+ && (p->p_type != PT_LOAD
+ || (abfd->flags & D_PAGED) == 0))
p->p_align = align;
}
if (! m->p_flags_valid)
{
p->p_flags |= PF_R;
- if ((flags & SEC_CODE) != 0)
+ if ((this_hdr->sh_flags & SHF_EXECINSTR) != 0)
p->p_flags |= PF_X;
- if ((flags & SEC_READONLY) == 0)
+ if ((this_hdr->sh_flags & SHF_WRITE) != 0)
p->p_flags |= PF_W;
}
}
- }
- /* Clear out any program headers we allocated but did not use. */
- for (; count < alloc; count++, p++)
- {
- memset (p, 0, sizeof *p);
- p->p_type = PT_NULL;
+ /* Check that all sections are in a PT_LOAD segment.
+ Don't check funky gdb generated core files. */
+ if (p->p_type == PT_LOAD && bfd_get_format (abfd) != bfd_core)
+ for (i = 0, secpp = m->sections; i < m->count; i++, secpp++)
+ {
+ Elf_Internal_Shdr *this_hdr;
+ asection *sec;
+
+ sec = *secpp;
+ this_hdr = &(elf_section_data(sec)->this_hdr);
+ if (this_hdr->sh_size != 0
+ && !ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, p))
+ {
+ (*_bfd_error_handler)
+ (_("%B: section `%A' can't be allocated in segment %d"),
+ abfd, sec, j);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ }
}
elf_tdata (abfd)->next_file_pos = off;
hdr = *hdrpp;
if (hdr->bfd_section != NULL
- && hdr->bfd_section->filepos != 0)
- hdr->sh_offset = hdr->bfd_section->filepos;
+ && (hdr->bfd_section->filepos != 0
+ || (hdr->sh_type == SHT_NOBITS
+ && hdr->contents == NULL)))
+ BFD_ASSERT (hdr->sh_offset == hdr->bfd_section->filepos);
else if ((hdr->sh_flags & SHF_ALLOC) != 0)
{
- ((*_bfd_error_handler)
- (_("%B: warning: allocated section `%s' not in segment"),
- abfd,
- (hdr->bfd_section == NULL
- ? "*unknown*"
- : hdr->bfd_section->name)));
- if ((abfd->flags & D_PAGED) != 0)
+ if (hdr->sh_size != 0)
+ ((*_bfd_error_handler)
+ (_("%B: warning: allocated section `%s' not in segment"),
+ abfd,
+ (hdr->bfd_section == NULL
+ ? "*unknown*"
+ : hdr->bfd_section->name)));
+ /* We don't need to page align empty sections. */
+ if ((abfd->flags & D_PAGED) != 0 && hdr->sh_size != 0)
off += vma_page_aligned_bias (hdr->sh_addr, off,
bed->maxpagesize);
else
if (! m->p_paddr_valid)
p->p_paddr = phdrs_paddr;
}
- else if (p->p_type == PT_GNU_RELRO)
- {
- Elf_Internal_Phdr *lp;
-
- for (lp = phdrs; lp < phdrs + count; ++lp)
- {
- if (lp->p_type == PT_LOAD
- && lp->p_vaddr <= link_info->relro_end
- && lp->p_vaddr >= link_info->relro_start
- && lp->p_vaddr + lp->p_filesz
- >= link_info->relro_end)
- break;
- }
-
- if (lp < phdrs + count
- && link_info->relro_end > lp->p_vaddr)
- {
- p->p_vaddr = lp->p_vaddr;
- p->p_paddr = lp->p_paddr;
- p->p_offset = lp->p_offset;
- p->p_filesz = link_info->relro_end - lp->p_vaddr;
- p->p_memsz = p->p_filesz;
- p->p_align = 1;
- p->p_flags = (lp->p_flags & ~PF_W);
- }
- else
- {
- memset (p, 0, sizeof *p);
- p->p_type = PT_NULL;
- }
- }
- }
- }
-
- elf_tdata (abfd)->next_file_pos = off;
-
- return TRUE;
-}
-
-/* Get the size of the program header.
-
- If this is called by the linker before any of the section VMA's are set, it
- can't calculate the correct value for a strange memory layout. This only
- happens when SIZEOF_HEADERS is used in a linker script. In this case,
- SORTED_HDRS is NULL and we assume the normal scenario of one text and one
- data segment (exclusive of .interp and .dynamic).
-
- ??? User written scripts must either not use SIZEOF_HEADERS, or assume there
- will be two segments. */
-
-static bfd_size_type
-get_program_header_size (bfd *abfd, struct bfd_link_info *info)
-{
- size_t segs;
- asection *s;
- const struct elf_backend_data *bed = get_elf_backend_data (abfd);
-
- /* We can't return a different result each time we're called. */
- if (elf_tdata (abfd)->program_header_size != 0)
- return elf_tdata (abfd)->program_header_size;
-
- if (elf_tdata (abfd)->segment_map != NULL)
- {
- struct elf_segment_map *m;
-
- segs = 0;
- for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
- ++segs;
- elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr;
- return elf_tdata (abfd)->program_header_size;
- }
-
- /* Assume we will need exactly two PT_LOAD segments: one for text
- and one for data. */
- segs = 2;
-
- s = bfd_get_section_by_name (abfd, ".interp");
- if (s != NULL && (s->flags & SEC_LOAD) != 0)
- {
- /* If we have a loadable interpreter section, we need a
- PT_INTERP segment. In this case, assume we also need a
- PT_PHDR segment, although that may not be true for all
- targets. */
- segs += 2;
- }
-
- if (bfd_get_section_by_name (abfd, ".dynamic") != NULL)
- {
- /* We need a PT_DYNAMIC segment. */
- ++segs;
- }
-
- if (elf_tdata (abfd)->eh_frame_hdr)
- {
- /* We need a PT_GNU_EH_FRAME segment. */
- ++segs;
- }
-
- if (elf_tdata (abfd)->stack_flags)
- {
- /* We need a PT_GNU_STACK segment. */
- ++segs;
- }
-
- if (elf_tdata (abfd)->relro)
- {
- /* We need a PT_GNU_RELRO segment. */
- ++segs;
- }
+ else if (p->p_type == PT_GNU_RELRO)
+ {
+ Elf_Internal_Phdr *lp;
- for (s = abfd->sections; s != NULL; s = s->next)
- {
- if ((s->flags & SEC_LOAD) != 0
- && strncmp (s->name, ".note", 5) == 0)
- {
- /* We need a PT_NOTE segment. */
- ++segs;
- }
- }
+ for (lp = phdrs; lp < phdrs + count; ++lp)
+ {
+ if (lp->p_type == PT_LOAD
+ && lp->p_vaddr <= link_info->relro_end
+ && lp->p_vaddr >= link_info->relro_start
+ && (lp->p_vaddr + lp->p_filesz
+ >= link_info->relro_end))
+ break;
+ }
- for (s = abfd->sections; s != NULL; s = s->next)
- {
- if (s->flags & SEC_THREAD_LOCAL)
- {
- /* We need a PT_TLS segment. */
- ++segs;
- break;
+ if (lp < phdrs + count
+ && link_info->relro_end > lp->p_vaddr)
+ {
+ p->p_vaddr = lp->p_vaddr;
+ p->p_paddr = lp->p_paddr;
+ p->p_offset = lp->p_offset;
+ p->p_filesz = link_info->relro_end - lp->p_vaddr;
+ p->p_memsz = p->p_filesz;
+ p->p_align = 1;
+ p->p_flags = (lp->p_flags & ~PF_W);
+ }
+ else
+ {
+ memset (p, 0, sizeof *p);
+ p->p_type = PT_NULL;
+ }
+ }
}
}
- /* Let the backend count up any program headers it might need. */
- if (bed->elf_backend_additional_program_headers)
- {
- int a;
-
- a = (*bed->elf_backend_additional_program_headers) (abfd, info);
- if (a == -1)
- abort ();
- segs += a;
- }
+ elf_tdata (abfd)->next_file_pos = off;
- elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr;
- return elf_tdata (abfd)->program_header_size;
+ return TRUE;
}
/* Work out the file positions of all the sections. This is called by
if (!assign_file_positions_for_non_load_sections (abfd, link_info))
return FALSE;
+ if (bed->elf_backend_modify_program_headers != NULL)
+ {
+ if (!(*bed->elf_backend_modify_program_headers) (abfd, link_info))
+ return FALSE;
+ }
+
/* Write out the program headers. */
alloc = tdata->program_header_size / bed->s->sizeof_phdr;
if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0
&& bfd_get_format (ibfd) == bfd_core \
&& s->vma == 0 && s->lma == 0 \
&& (bfd_vma) s->filepos >= p->p_offset \
- && ((bfd_vma) s->filepos + s->size \
+ && ((bfd_vma) s->filepos + s->size \
<= p->p_offset + p->p_filesz))
/* The complicated case when p_vaddr is 0 is to handle the Solaris
&& (s->flags & SEC_HAS_CONTENTS) != 0 \
&& s->size > 0 \
&& (bfd_vma) s->filepos >= p->p_offset \
- && ((bfd_vma) s->filepos + s->size \
+ && ((bfd_vma) s->filepos + s->size \
<= p->p_offset + p->p_filesz))
/* Decide if the given section should be included in the given segment.
7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments.
8. PT_DYNAMIC should not contain empty sections at the beginning
(with the possible exception of .dynamic). */
-#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed) \
+#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed) \
((((segment->p_paddr \
? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr) \
: IS_CONTAINED_BY_VMA (section, segment)) \
&& (section->flags & SEC_ALLOC) != 0) \
|| IS_COREFILE_NOTE (segment, section)) \
- && section->output_section != NULL \
&& segment->p_type != PT_GNU_STACK \
&& (segment->p_type != PT_TLS \
|| (section->flags & SEC_THREAD_LOCAL)) \
== 0)) \
&& ! section->segment_mark)
+/* If the output section of a section in the input segment is NULL,
+ it is removed from the corresponding output segment. */
+#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed) \
+ (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed) \
+ && section->output_section != NULL)
+
/* Returns TRUE iff seg1 starts after the end of seg2. */
#define SEGMENT_AFTER_SEGMENT(seg1, seg2, field) \
(seg1->field >= SEGMENT_END (seg2, seg2->field))
bfd_vma suggested_lma;
unsigned int j;
bfd_size_type amt;
+ asection * first_section;
if (segment->p_type == PT_NULL)
continue;
+ first_section = NULL;
/* Compute how many sections might be placed into this segment. */
for (section = ibfd->sections, section_count = 0;
section != NULL;
section = section->next)
- if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed))
- ++section_count;
+ {
+ /* Find the first section in the input segment, which may be
+ removed from the corresponding output segment. */
+ if (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed))
+ {
+ if (first_section == NULL)
+ first_section = section;
+ if (section->output_section != NULL)
+ ++section_count;
+ }
+ }
/* Allocate a segment map big enough to contain
all of the sections we have selected. */
amt = sizeof (struct elf_segment_map);
amt += ((bfd_size_type) section_count - 1) * sizeof (asection *);
- map = bfd_alloc (obfd, amt);
+ map = bfd_zalloc (obfd, amt);
if (map == NULL)
return FALSE;
map->p_type = segment->p_type;
map->p_flags = segment->p_flags;
map->p_flags_valid = 1;
- map->p_paddr = segment->p_paddr;
- map->p_paddr_valid = 1;
+
+ /* If the first section in the input segment is removed, there is
+ no need to preserve segment physical address in the corresponding
+ output segment. */
+ if (!first_section || first_section->output_section != NULL)
+ {
+ map->p_paddr = segment->p_paddr;
+ map->p_paddr_valid = 1;
+ }
/* Determine if this segment contains the ELF file header
and if it contains the program headers themselves. */
map->count = section_count;
*pointer_to_map = map;
pointer_to_map = &map->next;
-
+
+ if (matching_lma != map->p_paddr
+ && !map->includes_filehdr && !map->includes_phdrs)
+ /* There is some padding before the first section in the
+ segment. So, we must account for that in the output
+ segment's vma. */
+ map->p_vaddr_offset = matching_lma - map->p_paddr;
+
free (sections);
continue;
}
#undef IS_CONTAINED_BY_LMA
#undef IS_COREFILE_NOTE
#undef IS_SOLARIS_PT_INTERP
+#undef IS_SECTION_IN_INPUT_SEGMENT
#undef INCLUDE_SECTION_IN_SEGMENT
#undef SEGMENT_AFTER_SEGMENT
#undef SEGMENT_OVERLAPS
unsigned int section_count;
bfd_size_type amt;
Elf_Internal_Shdr *this_hdr;
+ asection *first_section = NULL;
/* FIXME: Do we need to copy PT_NULL segment? */
if (segment->p_type == PT_NULL)
{
this_hdr = &(elf_section_data(section)->this_hdr);
if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment))
- section_count++;
+ {
+ if (!first_section)
+ first_section = section;
+ section_count++;
+ }
}
/* Allocate a segment map big enough to contain
amt = sizeof (struct elf_segment_map);
if (section_count != 0)
amt += ((bfd_size_type) section_count - 1) * sizeof (asection *);
- map = bfd_alloc (obfd, amt);
+ map = bfd_zalloc (obfd, amt);
if (map == NULL)
return FALSE;
map->p_paddr_valid = 1;
map->p_align = segment->p_align;
map->p_align_valid = 1;
+ map->p_vaddr_offset = 0;
/* Determine if this segment contains the ELF file header
and if it contains the program headers themselves. */
phdr_included = TRUE;
}
+ if (!map->includes_phdrs && !map->includes_filehdr)
+ /* There is some other padding before the first section. */
+ map->p_vaddr_offset = ((first_section ? first_section->lma : 0)
+ - segment->p_paddr);
+
if (section_count != 0)
{
unsigned int isec = 0;
- for (section = ibfd->sections;
+ for (section = first_section;
section != NULL;
section = section->next)
{
this_hdr = &(elf_section_data(section)->this_hdr);
if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment))
- map->sections[isec++] = section->output_section;
+ {
+ map->sections[isec++] = section->output_section;
+ if (isec == section_count)
+ break;
+ }
}
}
if (ibfd->xvec == obfd->xvec)
{
- /* Check if any sections in the input BFD covered by ELF program
- header are changed. */
+ /* Check to see if any sections in the input BFD
+ covered by ELF program header have changed. */
Elf_Internal_Phdr *segment;
asection *section, *osec;
unsigned int i, num_segments;
i < num_segments;
i++, segment++)
{
+ /* PR binutils/3535. The Solaris linker always sets the p_paddr
+ and p_memsz fields of special segments (DYNAMIC, INTERP) to 0
+ which severly confuses things, so always regenerate the segment
+ map in this case. */
+ if (segment->p_paddr == 0
+ && segment->p_memsz == 0
+ && (segment->p_type == PT_INTERP || segment->p_type == PT_DYNAMIC))
+ goto rewrite;
+
for (section = ibfd->sections;
section != NULL; section = section->next)
{
}
}
- /* Check to see if any output section doesn't come from the
+ /* Check to see if any output section do not come from the
input BFD. */
for (section = obfd->sections; section != NULL;
section = section->next)
output BFD section flags have been set to something different.
elf_fake_sections will set ELF section type based on BFD
section flags. */
- if (osec->flags == isec->flags
- || (osec->flags == 0 && elf_section_type (osec) == SHT_NULL))
+ if (elf_section_type (osec) == SHT_NULL
+ && (osec->flags == isec->flags || !osec->flags))
elf_section_type (osec) = elf_section_type (isec);
+ /* FIXME: Is this correct for all OS/PROC specific flags? */
+ elf_section_flags (osec) |= (elf_section_flags (isec)
+ & (SHF_MASKOS | SHF_MASKPROC));
+
/* Set things up for objcopy and relocatable link. The output
SHT_GROUP section will have its elf_next_in_group pointing back
to the input group members. Ignore linker created group section.
bfd_boolean
_bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd)
{
+ asection *isec;
+
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return TRUE;
return FALSE;
}
+ /* _bfd_elf_copy_private_section_data copied over the SHF_GROUP flag
+ but this might be wrong if we deleted the group section. */
+ for (isec = ibfd->sections; isec != NULL; isec = isec->next)
+ if (elf_section_type (isec) == SHT_GROUP
+ && isec->output_section == NULL)
+ {
+ asection *first = elf_next_in_group (isec);
+ asection *s = first;
+ while (s != NULL)
+ {
+ if (s->output_section != NULL)
+ {
+ elf_section_flags (s->output_section) &= ~SHF_GROUP;
+ elf_group_name (s->output_section) = NULL;
+ }
+ s = elf_next_in_group (s);
+ if (s == first)
+ break;
+ }
+ }
+
return TRUE;
}
type = STT_FUNC;
else if ((flags & BSF_OBJECT) != 0)
type = STT_OBJECT;
+ else if ((flags & BSF_RELC) != 0)
+ type = STT_RELC;
+ else if ((flags & BSF_SRELC) != 0)
+ type = STT_SRELC;
else
type = STT_NOTYPE;
int
_bfd_elf_sizeof_headers (bfd *abfd, struct bfd_link_info *info)
{
- int ret;
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ int ret = bed->s->sizeof_ehdr;
- ret = get_elf_backend_data (abfd)->s->sizeof_ehdr;
if (!info->relocatable)
- ret += get_program_header_size (abfd, info);
+ {
+ bfd_size_type phdr_size = elf_tdata (abfd)->program_header_size;
+
+ if (phdr_size == (bfd_size_type) -1)
+ {
+ struct elf_segment_map *m;
+
+ phdr_size = 0;
+ for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
+ phdr_size += bed->s->sizeof_phdr;
+
+ if (phdr_size == 0)
+ phdr_size = get_program_header_size (abfd, info);
+ }
+
+ elf_tdata (abfd)->program_header_size = phdr_size;
+ ret += phdr_size;
+ }
+
return ret;
}
/* Function: elfcore_write_note
Inputs:
- buffer to hold note
+ buffer to hold note, and current size of buffer
name of note
type of note
data for note
size of data for note
+ Writes note to end of buffer. ELF64 notes are written exactly as
+ for ELF32, despite the current (as of 2006) ELF gabi specifying
+ that they ought to have 8-byte namesz and descsz field, and have
+ 8-byte alignment. Other writers, eg. Linux kernel, do the same.
+
Return:
- End of buffer containing note. */
+ Pointer to realloc'd buffer, *BUFSIZ updated. */
char *
-elfcore_write_note (bfd *abfd,
+elfcore_write_note (bfd *abfd,
char *buf,
- int *bufsiz,
+ int *bufsiz,
const char *name,
- int type,
+ int type,
const void *input,
- int size)
+ int size)
{
Elf_External_Note *xnp;
size_t namesz;
- size_t pad;
size_t newspace;
- char *p, *dest;
+ char *dest;
namesz = 0;
- pad = 0;
if (name != NULL)
- {
- const struct elf_backend_data *bed;
-
- namesz = strlen (name) + 1;
- bed = get_elf_backend_data (abfd);
- pad = -namesz & ((1 << bed->s->log_file_align) - 1);
- }
+ namesz = strlen (name) + 1;
- newspace = 12 + namesz + pad + size;
+ newspace = 12 + ((namesz + 3) & -4) + ((size + 3) & -4);
- p = realloc (buf, *bufsiz + newspace);
- dest = p + *bufsiz;
+ buf = realloc (buf, *bufsiz + newspace);
+ dest = buf + *bufsiz;
*bufsiz += newspace;
xnp = (Elf_External_Note *) dest;
H_PUT_32 (abfd, namesz, xnp->namesz);
{
memcpy (dest, name, namesz);
dest += namesz;
- while (pad != 0)
+ while (namesz & 3)
{
*dest++ = '\0';
- --pad;
+ ++namesz;
}
}
memcpy (dest, input, size);
- return p;
+ dest += size;
+ while (size & 3)
+ {
+ *dest++ = '\0';
+ ++size;
+ }
+ return buf;
}
#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T)
const char *fname,
const char *psargs)
{
- int note_type;
- char *note_name = "CORE";
+ const char *note_name = "CORE";
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+ if (bed->elf_backend_write_core_note != NULL)
+ {
+ char *ret;
+ ret = (*bed->elf_backend_write_core_note) (abfd, buf, bufsiz,
+ NT_PRPSINFO, fname, psargs);
+ if (ret != NULL)
+ return ret;
+ }
+
+#if defined (HAVE_PRPSINFO32_T) || defined (HAVE_PSINFO32_T)
+ if (bed->s->elfclass == ELFCLASS32)
+ {
+#if defined (HAVE_PSINFO32_T)
+ psinfo32_t data;
+ int note_type = NT_PSINFO;
+#else
+ prpsinfo32_t data;
+ int note_type = NT_PRPSINFO;
+#endif
+ memset (&data, 0, sizeof (data));
+ strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
+ strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, note_type, &data, sizeof (data));
+ }
+ else
+#endif
+ {
#if defined (HAVE_PSINFO_T)
- psinfo_t data;
- note_type = NT_PSINFO;
+ psinfo_t data;
+ int note_type = NT_PSINFO;
#else
- prpsinfo_t data;
- note_type = NT_PRPSINFO;
+ prpsinfo_t data;
+ int note_type = NT_PRPSINFO;
#endif
- memset (&data, 0, sizeof (data));
- strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
- strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
- return elfcore_write_note (abfd, buf, bufsiz,
- note_name, note_type, &data, sizeof (data));
+ memset (&data, 0, sizeof (data));
+ strncpy (data.pr_fname, fname, sizeof (data.pr_fname));
+ strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs));
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, note_type, &data, sizeof (data));
+ }
}
#endif /* PSINFO_T or PRPSINFO_T */
int cursig,
const void *gregs)
{
- prstatus_t prstat;
- char *note_name = "CORE";
+ const char *note_name = "CORE";
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
- memset (&prstat, 0, sizeof (prstat));
- prstat.pr_pid = pid;
- prstat.pr_cursig = cursig;
- memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
- return elfcore_write_note (abfd, buf, bufsiz,
- note_name, NT_PRSTATUS, &prstat, sizeof (prstat));
+ if (bed->elf_backend_write_core_note != NULL)
+ {
+ char *ret;
+ ret = (*bed->elf_backend_write_core_note) (abfd, buf, bufsiz,
+ NT_PRSTATUS,
+ pid, cursig, gregs);
+ if (ret != NULL)
+ return ret;
+ }
+
+#if defined (HAVE_PRSTATUS32_T)
+ if (bed->s->elfclass == ELFCLASS32)
+ {
+ prstatus32_t prstat;
+
+ memset (&prstat, 0, sizeof (prstat));
+ prstat.pr_pid = pid;
+ prstat.pr_cursig = cursig;
+ memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
+ return elfcore_write_note (abfd, buf, bufsiz, note_name,
+ NT_PRSTATUS, &prstat, sizeof (prstat));
+ }
+ else
+#endif
+ {
+ prstatus_t prstat;
+
+ memset (&prstat, 0, sizeof (prstat));
+ prstat.pr_pid = pid;
+ prstat.pr_cursig = cursig;
+ memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg));
+ return elfcore_write_note (abfd, buf, bufsiz, note_name,
+ NT_PRSTATUS, &prstat, sizeof (prstat));
+ }
}
#endif /* HAVE_PRSTATUS_T */
const void *gregs)
{
lwpstatus_t lwpstat;
- char *note_name = "CORE";
+ const char *note_name = "CORE";
memset (&lwpstat, 0, sizeof (lwpstat));
lwpstat.pr_lwpid = pid >> 16;
int cursig ATTRIBUTE_UNUSED,
const void *gregs ATTRIBUTE_UNUSED)
{
- pstatus_t pstat;
- char *note_name = "CORE";
+ const char *note_name = "CORE";
+#if defined (HAVE_PSTATUS32_T)
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
- memset (&pstat, 0, sizeof (pstat));
- pstat.pr_pid = pid & 0xffff;
- buf = elfcore_write_note (abfd, buf, bufsiz, note_name,
- NT_PSTATUS, &pstat, sizeof (pstat));
- return buf;
+ if (bed->s->elfclass == ELFCLASS32)
+ {
+ pstatus32_t pstat;
+
+ memset (&pstat, 0, sizeof (pstat));
+ pstat.pr_pid = pid & 0xffff;
+ buf = elfcore_write_note (abfd, buf, bufsiz, note_name,
+ NT_PSTATUS, &pstat, sizeof (pstat));
+ return buf;
+ }
+ else
+#endif
+ {
+ pstatus_t pstat;
+
+ memset (&pstat, 0, sizeof (pstat));
+ pstat.pr_pid = pid & 0xffff;
+ buf = elfcore_write_note (abfd, buf, bufsiz, note_name,
+ NT_PSTATUS, &pstat, sizeof (pstat));
+ return buf;
+ }
}
#endif /* HAVE_PSTATUS_T */
const void *fpregs,
int size)
{
- char *note_name = "CORE";
+ const char *note_name = "CORE";
return elfcore_write_note (abfd, buf, bufsiz,
note_name, NT_FPREGSET, fpregs, size);
}
in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4);
in.descpos = offset + (in.descdata - buf);
- if (strncmp (in.namedata, "NetBSD-CORE", 11) == 0)
+ if (CONST_STRNEQ (in.namedata, "NetBSD-CORE"))
{
if (! elfcore_grok_netbsd_note (abfd, &in))
goto error;
}
- else if (strncmp (in.namedata, "QNX", 3) == 0)
+ else if (CONST_STRNEQ (in.namedata, "QNX"))
{
if (! elfcore_grok_nto_note (abfd, &in))
goto error;
return n;
}
-/* Sort symbol by binding and section. We want to put definitions
- sorted by section at the beginning. */
-
-static int
-elf_sort_elf_symbol (const void *arg1, const void *arg2)
+struct elf_symbuf_symbol
{
- const Elf_Internal_Sym *s1;
- const Elf_Internal_Sym *s2;
- int shndx;
-
- /* Make sure that undefined symbols are at the end. */
- s1 = (const Elf_Internal_Sym *) arg1;
- if (s1->st_shndx == SHN_UNDEF)
- return 1;
- s2 = (const Elf_Internal_Sym *) arg2;
- if (s2->st_shndx == SHN_UNDEF)
- return -1;
-
- /* Sorted by section index. */
- shndx = s1->st_shndx - s2->st_shndx;
- if (shndx != 0)
- return shndx;
+ unsigned long st_name; /* Symbol name, index in string tbl */
+ unsigned char st_info; /* Type and binding attributes */
+ unsigned char st_other; /* Visibilty, and target specific */
+};
- /* Sorted by binding. */
- return ELF_ST_BIND (s1->st_info) - ELF_ST_BIND (s2->st_info);
-}
+struct elf_symbuf_head
+{
+ struct elf_symbuf_symbol *ssym;
+ bfd_size_type count;
+ unsigned int st_shndx;
+};
struct elf_symbol
{
- Elf_Internal_Sym *sym;
+ union
+ {
+ Elf_Internal_Sym *isym;
+ struct elf_symbuf_symbol *ssym;
+ } u;
const char *name;
};
+/* Sort references to symbols by ascending section number. */
+
+static int
+elf_sort_elf_symbol (const void *arg1, const void *arg2)
+{
+ const Elf_Internal_Sym *s1 = *(const Elf_Internal_Sym **) arg1;
+ const Elf_Internal_Sym *s2 = *(const Elf_Internal_Sym **) arg2;
+
+ return s1->st_shndx - s2->st_shndx;
+}
+
static int
elf_sym_name_compare (const void *arg1, const void *arg2)
{
return strcmp (s1->name, s2->name);
}
+static struct elf_symbuf_head *
+elf_create_symbuf (bfd_size_type symcount, Elf_Internal_Sym *isymbuf)
+{
+ Elf_Internal_Sym **ind, **indbufend, **indbuf
+ = bfd_malloc2 (symcount, sizeof (*indbuf));
+ struct elf_symbuf_symbol *ssym;
+ struct elf_symbuf_head *ssymbuf, *ssymhead;
+ bfd_size_type i, shndx_count;
+
+ if (indbuf == NULL)
+ return NULL;
+
+ for (ind = indbuf, i = 0; i < symcount; i++)
+ if (isymbuf[i].st_shndx != SHN_UNDEF)
+ *ind++ = &isymbuf[i];
+ indbufend = ind;
+
+ qsort (indbuf, indbufend - indbuf, sizeof (Elf_Internal_Sym *),
+ elf_sort_elf_symbol);
+
+ shndx_count = 0;
+ if (indbufend > indbuf)
+ for (ind = indbuf, shndx_count++; ind < indbufend - 1; ind++)
+ if (ind[0]->st_shndx != ind[1]->st_shndx)
+ shndx_count++;
+
+ ssymbuf = bfd_malloc ((shndx_count + 1) * sizeof (*ssymbuf)
+ + (indbufend - indbuf) * sizeof (*ssymbuf));
+ if (ssymbuf == NULL)
+ {
+ free (indbuf);
+ return NULL;
+ }
+
+ ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count);
+ ssymbuf->ssym = NULL;
+ ssymbuf->count = shndx_count;
+ ssymbuf->st_shndx = 0;
+ for (ssymhead = ssymbuf, ind = indbuf; ind < indbufend; ssym++, ind++)
+ {
+ if (ind == indbuf || ssymhead->st_shndx != (*ind)->st_shndx)
+ {
+ ssymhead++;
+ ssymhead->ssym = ssym;
+ ssymhead->count = 0;
+ ssymhead->st_shndx = (*ind)->st_shndx;
+ }
+ ssym->st_name = (*ind)->st_name;
+ ssym->st_info = (*ind)->st_info;
+ ssym->st_other = (*ind)->st_other;
+ ssymhead->count++;
+ }
+ BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count);
+
+ free (indbuf);
+ return ssymbuf;
+}
+
/* Check if 2 sections define the same set of local and global
symbols. */
bfd_boolean
-bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2)
+bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2,
+ struct bfd_link_info *info)
{
bfd *bfd1, *bfd2;
const struct elf_backend_data *bed1, *bed2;
Elf_Internal_Shdr *hdr1, *hdr2;
bfd_size_type symcount1, symcount2;
Elf_Internal_Sym *isymbuf1, *isymbuf2;
- Elf_Internal_Sym *isymstart1 = NULL, *isymstart2 = NULL, *isym;
- Elf_Internal_Sym *isymend;
- struct elf_symbol *symp, *symtable1 = NULL, *symtable2 = NULL;
+ struct elf_symbuf_head *ssymbuf1, *ssymbuf2;
+ Elf_Internal_Sym *isym, *isymend;
+ struct elf_symbol *symtable1 = NULL, *symtable2 = NULL;
bfd_size_type count1, count2, i;
int shndx1, shndx2;
bfd_boolean result;
/* If both are .gnu.linkonce sections, they have to have the same
section name. */
- if (strncmp (sec1->name, ".gnu.linkonce",
- sizeof ".gnu.linkonce" - 1) == 0
- && strncmp (sec2->name, ".gnu.linkonce",
- sizeof ".gnu.linkonce" - 1) == 0)
+ if (CONST_STRNEQ (sec1->name, ".gnu.linkonce")
+ && CONST_STRNEQ (sec2->name, ".gnu.linkonce"))
return strcmp (sec1->name + sizeof ".gnu.linkonce",
sec2->name + sizeof ".gnu.linkonce") == 0;
if (symcount1 == 0 || symcount2 == 0)
return FALSE;
- isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
- NULL, NULL, NULL);
- isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0,
- NULL, NULL, NULL);
-
result = FALSE;
- if (isymbuf1 == NULL || isymbuf2 == NULL)
- goto done;
+ isymbuf1 = NULL;
+ isymbuf2 = NULL;
+ ssymbuf1 = elf_tdata (bfd1)->symbuf;
+ ssymbuf2 = elf_tdata (bfd2)->symbuf;
- /* Sort symbols by binding and section. Global definitions are at
- the beginning. */
- qsort (isymbuf1, symcount1, sizeof (Elf_Internal_Sym),
- elf_sort_elf_symbol);
- qsort (isymbuf2, symcount2, sizeof (Elf_Internal_Sym),
- elf_sort_elf_symbol);
+ if (ssymbuf1 == NULL)
+ {
+ isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
+ NULL, NULL, NULL);
+ if (isymbuf1 == NULL)
+ goto done;
- /* Count definitions in the section. */
- count1 = 0;
- for (isym = isymbuf1, isymend = isym + symcount1;
- isym < isymend; isym++)
+ if (!info->reduce_memory_overheads)
+ elf_tdata (bfd1)->symbuf = ssymbuf1
+ = elf_create_symbuf (symcount1, isymbuf1);
+ }
+
+ if (ssymbuf1 == NULL || ssymbuf2 == NULL)
{
- if (isym->st_shndx == (unsigned int) shndx1)
- {
- if (count1 == 0)
- isymstart1 = isym;
- count1++;
- }
+ isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0,
+ NULL, NULL, NULL);
+ if (isymbuf2 == NULL)
+ goto done;
- if (count1 && isym->st_shndx != (unsigned int) shndx1)
- break;
+ if (ssymbuf1 != NULL && !info->reduce_memory_overheads)
+ elf_tdata (bfd2)->symbuf = ssymbuf2
+ = elf_create_symbuf (symcount2, isymbuf2);
}
- count2 = 0;
- for (isym = isymbuf2, isymend = isym + symcount2;
- isym < isymend; isym++)
+ if (ssymbuf1 != NULL && ssymbuf2 != NULL)
{
- if (isym->st_shndx == (unsigned int) shndx2)
+ /* Optimized faster version. */
+ bfd_size_type lo, hi, mid;
+ struct elf_symbol *symp;
+ struct elf_symbuf_symbol *ssym, *ssymend;
+
+ lo = 0;
+ hi = ssymbuf1->count;
+ ssymbuf1++;
+ count1 = 0;
+ while (lo < hi)
+ {
+ mid = (lo + hi) / 2;
+ if ((unsigned int) shndx1 < ssymbuf1[mid].st_shndx)
+ hi = mid;
+ else if ((unsigned int) shndx1 > ssymbuf1[mid].st_shndx)
+ lo = mid + 1;
+ else
+ {
+ count1 = ssymbuf1[mid].count;
+ ssymbuf1 += mid;
+ break;
+ }
+ }
+
+ lo = 0;
+ hi = ssymbuf2->count;
+ ssymbuf2++;
+ count2 = 0;
+ while (lo < hi)
{
- if (count2 == 0)
- isymstart2 = isym;
- count2++;
+ mid = (lo + hi) / 2;
+ if ((unsigned int) shndx2 < ssymbuf2[mid].st_shndx)
+ hi = mid;
+ else if ((unsigned int) shndx2 > ssymbuf2[mid].st_shndx)
+ lo = mid + 1;
+ else
+ {
+ count2 = ssymbuf2[mid].count;
+ ssymbuf2 += mid;
+ break;
+ }
}
- if (count2 && isym->st_shndx != (unsigned int) shndx2)
- break;
+ if (count1 == 0 || count2 == 0 || count1 != count2)
+ goto done;
+
+ symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol));
+ symtable2 = bfd_malloc (count2 * sizeof (struct elf_symbol));
+ if (symtable1 == NULL || symtable2 == NULL)
+ goto done;
+
+ symp = symtable1;
+ for (ssym = ssymbuf1->ssym, ssymend = ssym + count1;
+ ssym < ssymend; ssym++, symp++)
+ {
+ symp->u.ssym = ssym;
+ symp->name = bfd_elf_string_from_elf_section (bfd1,
+ hdr1->sh_link,
+ ssym->st_name);
+ }
+
+ symp = symtable2;
+ for (ssym = ssymbuf2->ssym, ssymend = ssym + count2;
+ ssym < ssymend; ssym++, symp++)
+ {
+ symp->u.ssym = ssym;
+ symp->name = bfd_elf_string_from_elf_section (bfd2,
+ hdr2->sh_link,
+ ssym->st_name);
+ }
+
+ /* Sort symbol by name. */
+ qsort (symtable1, count1, sizeof (struct elf_symbol),
+ elf_sym_name_compare);
+ qsort (symtable2, count1, sizeof (struct elf_symbol),
+ elf_sym_name_compare);
+
+ for (i = 0; i < count1; i++)
+ /* Two symbols must have the same binding, type and name. */
+ if (symtable1 [i].u.ssym->st_info != symtable2 [i].u.ssym->st_info
+ || symtable1 [i].u.ssym->st_other != symtable2 [i].u.ssym->st_other
+ || strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
+ goto done;
+
+ result = TRUE;
+ goto done;
}
- if (count1 == 0 || count2 == 0 || count1 != count2)
+ symtable1 = bfd_malloc (symcount1 * sizeof (struct elf_symbol));
+ symtable2 = bfd_malloc (symcount2 * sizeof (struct elf_symbol));
+ if (symtable1 == NULL || symtable2 == NULL)
goto done;
- symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol));
- symtable2 = bfd_malloc (count1 * sizeof (struct elf_symbol));
+ /* Count definitions in the section. */
+ count1 = 0;
+ for (isym = isymbuf1, isymend = isym + symcount1; isym < isymend; isym++)
+ if (isym->st_shndx == (unsigned int) shndx1)
+ symtable1[count1++].u.isym = isym;
- if (symtable1 == NULL || symtable2 == NULL)
+ count2 = 0;
+ for (isym = isymbuf2, isymend = isym + symcount2; isym < isymend; isym++)
+ if (isym->st_shndx == (unsigned int) shndx2)
+ symtable2[count2++].u.isym = isym;
+
+ if (count1 == 0 || count2 == 0 || count1 != count2)
goto done;
- symp = symtable1;
- for (isym = isymstart1, isymend = isym + count1;
- isym < isymend; isym++)
- {
- symp->sym = isym;
- symp->name = bfd_elf_string_from_elf_section (bfd1,
- hdr1->sh_link,
- isym->st_name);
- symp++;
- }
-
- symp = symtable2;
- for (isym = isymstart2, isymend = isym + count1;
- isym < isymend; isym++)
- {
- symp->sym = isym;
- symp->name = bfd_elf_string_from_elf_section (bfd2,
- hdr2->sh_link,
- isym->st_name);
- symp++;
- }
-
+ for (i = 0; i < count1; i++)
+ symtable1[i].name
+ = bfd_elf_string_from_elf_section (bfd1, hdr1->sh_link,
+ symtable1[i].u.isym->st_name);
+
+ for (i = 0; i < count2; i++)
+ symtable2[i].name
+ = bfd_elf_string_from_elf_section (bfd2, hdr2->sh_link,
+ symtable2[i].u.isym->st_name);
+
/* Sort symbol by name. */
qsort (symtable1, count1, sizeof (struct elf_symbol),
elf_sym_name_compare);
for (i = 0; i < count1; i++)
/* Two symbols must have the same binding, type and name. */
- if (symtable1 [i].sym->st_info != symtable2 [i].sym->st_info
- || symtable1 [i].sym->st_other != symtable2 [i].sym->st_other
+ if (symtable1 [i].u.isym->st_info != symtable2 [i].u.isym->st_info
+ || symtable1 [i].u.isym->st_other != symtable2 [i].u.isym->st_other
|| strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
goto done;
return elf_section_type (asec) == elf_section_type (bsec);
}
+
+void
+_bfd_elf_set_osabi (bfd * abfd,
+ struct bfd_link_info * link_info ATTRIBUTE_UNUSED)
+{
+ Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form. */
+
+ i_ehdrp = elf_elfheader (abfd);
+
+ i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
+}
+
+
+/* Return TRUE for ELF symbol types that represent functions.
+ This is the default version of this function, which is sufficient for
+ most targets. It returns true if TYPE is STT_FUNC. */
+
+bfd_boolean
+_bfd_elf_is_function_type (unsigned int type)
+{
+ return (type == STT_FUNC);
+}