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;
}
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)
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);
table->bucketcount = 0;
table->needed = NULL;
table->hgot = NULL;
+ table->hplt = NULL;
table->merge_info = NULL;
memset (&table->stab_info, 0, sizeof (table->stab_info));
memset (&table->eh_info, 0, sizeof (table->eh_info));
}
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))
"`%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[] =
case SHT_GROUP:
this_hdr->sh_entsize = 4;
break;
+
+ case SHT_GNU_HASH:
+ this_hdr->sh_entsize = bed->s->arch_size == 64 ? 0 : 4;
+ break;
}
if ((asect->flags & SEC_ALLOC) != 0)
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)
- {
- /* 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))
+ i = 0;
+ for (s = abfd->sections; s != NULL; s = s->next)
{
- /* 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;
+ }
+
+ 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. */
Elf_Internal_Phdr *p;
file_ptr off, voff;
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;
- }
- }
-
- 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));
.tbss, we need to look at the next section to decide
whether the segment has any loadable sections. */
i = 0;
- while ((m->sections[i]->flags & SEC_LOAD) == 0)
+ while ((m->sections[i]->flags & SEC_LOAD) == 0
+ && (m->sections[i]->flags & SEC_HAS_CONTENTS) == 0)
{
if ((m->sections[i]->flags & SEC_THREAD_LOCAL) == 0
|| ++i >= m->count)
{
if (p->p_type == PT_LOAD)
{
- sec->filepos = off;
+ sec->filepos = off + voff;
/* 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
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
+ && (p->p_type != PT_LOAD
+ || (abfd->flags & D_PAGED) == 0))
p->p_align = align;
}
}
}
- /* 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;
- }
-
elf_tdata (abfd)->next_file_pos = off;
return TRUE;
}
hdr = *hdrpp;
if (hdr->bfd_section != NULL
- && hdr->bfd_section->filepos != 0)
+ && (hdr->bfd_section->filepos != 0
+ || (hdr->sh_type == SHT_NOBITS
+ && hdr->contents == NULL)))
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 (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)
+ && (lp->p_vaddr + lp->p_filesz
+ >= link_info->relro_end))
break;
}
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;
- }
-
- 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 (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. */
- 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)->program_header_size = segs * bed->s->sizeof_phdr;
- return elf_tdata (abfd)->program_header_size;
-}
-
/* Work out the file positions of all the sections. This is called by
_bfd_elf_compute_section_file_positions. All the section sizes and
VMAs must be known before this is called.
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
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;
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;
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))
- elf_section_type (osec) = elf_section_type (isec);
+ if (osec->flags == isec->flags || !osec->flags)
+ {
+ BFD_ASSERT (osec->flags == isec->flags
+ || (!osec->flags
+ && elf_section_type (osec) == SHT_NULL));
+ 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
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;
}
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;
}
namesz = strlen (name) + 1;
bed = get_elf_backend_data (abfd);
- pad = -namesz & ((1 << bed->s->log_file_align) - 1);
+ pad = -namesz & 3;
}
newspace = 12 + namesz + pad + 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;
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;
/* 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 = elf_tdata (bfd1)->symbuf;
+ isymbuf2 = 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 (isymbuf1 == NULL)
+ {
+ isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
+ NULL, NULL, NULL);
+ if (isymbuf1 == NULL)
+ goto done;
+ /* Sort symbols by binding and section. Global definitions are at
+ the beginning. */
+ qsort (isymbuf1, symcount1, sizeof (Elf_Internal_Sym),
+ elf_sort_elf_symbol);
+ if (!info->reduce_memory_overheads)
+ elf_tdata (bfd1)->symbuf = isymbuf1;
+ }
+
+ if (isymbuf2 == NULL)
+ {
+ isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0,
+ NULL, NULL, NULL);
+ if (isymbuf2 == NULL)
+ goto done;
+ /* Sort symbols by binding and section. Global definitions are at
+ the beginning. */
+ qsort (isymbuf2, symcount2, sizeof (Elf_Internal_Sym),
+ elf_sort_elf_symbol);
+ if (!info->reduce_memory_overheads)
+ elf_tdata (bfd2)->symbuf = isymbuf2;
+ }
/* Count definitions in the section. */
count1 = 0;
free (symtable1);
if (symtable2)
free (symtable2);
- if (isymbuf1)
- free (isymbuf1);
- if (isymbuf2)
- free (isymbuf2);
+ if (info->reduce_memory_overheads)
+ {
+ if (isymbuf1)
+ free (isymbuf1);
+ if (isymbuf2)
+ free (isymbuf2);
+ }
return result;
}