/* 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.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
/*
SECTION
/* 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
#include "elf-bfd.h"
#include "libiberty.h"
+#include "safe-ctype.h"
static int elf_sort_sections (const void *, const void *);
static bfd_boolean assign_file_positions_except_relocs (bfd *, struct bfd_link_info *);
static bfd_boolean prep_headers (bfd *);
static bfd_boolean swap_out_syms (bfd *, struct bfd_strtab_hash **, int) ;
-static bfd_boolean elfcore_read_notes (bfd *, file_ptr, bfd_size_type) ;
+static bfd_boolean elf_read_notes (bfd *, file_ptr, bfd_size_type) ;
+static bfd_boolean elf_parse_notes (bfd *abfd, char *buf, size_t size,
+ file_ptr offset);
/* Swap version information in and out. The version information is
currently size independent. If that ever changes, this code will
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] == '.')
{
int i = name [1] - 'd';
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;
if (! bfd_set_section_flags (abfd, newsect, flags))
return FALSE;
+ /* We do not parse the PT_NOTE segments as we are interested even in the
+ separate debug info files which may have the segments offsets corrupted.
+ PT_NOTEs from the core files are currently not parsed using BFD. */
+ if (hdr->sh_type == SHT_NOTE)
+ {
+ char *contents;
+
+ contents = bfd_malloc (hdr->sh_size);
+ if (!contents)
+ return FALSE;
+
+ if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0,
+ hdr->sh_size)
+ || !elf_parse_notes (abfd, contents, hdr->sh_size, -1))
+ {
+ free (contents);
+ return FALSE;
+ }
+
+ free (contents);
+ }
+
if ((flags & SEC_ALLOC) != 0)
{
Elf_Internal_Phdr *phdr;
unsigned int i;
/* Look through the phdrs to see if we need to adjust the lma.
- If all the p_paddr fields are zero, we ignore them, since
- some ELF linkers produce such output. */
+ If all the p_paddr fields are zero, we ignore them, since
+ some ELF linkers produce such output. */
phdr = elf_tdata (abfd)->phdr;
for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
{
refuse to set the LMA if it was 0. This is wrong
though, as a perfectly valid initialised segment can
have a p_paddr of zero. Some architectures, eg ARM,
- place special significance on the address 0 and
- executables need to be able to have a segment which
- covers this address. */
+ place special significance on the address 0 and
+ executables need to be able to have a segment which
+ covers this address. */
if (phdr->p_type == PT_LOAD
&& (bfd_vma) hdr->sh_offset >= phdr->p_offset
&& (hdr->sh_offset + hdr->sh_size
return bfd_reloc_continue;
}
\f
-/* Make sure sec_info_type is cleared if sec_info is cleared too. */
-
-static void
-merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED,
- asection *sec)
-{
- BFD_ASSERT (sec->sec_info_type == ELF_INFO_TYPE_MERGE);
- sec->sec_info_type = ELF_INFO_TYPE_NONE;
-}
-
-/* Finish SHF_MERGE section merging. */
-
-bfd_boolean
-_bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info)
-{
- bfd *ibfd;
- asection *sec;
-
- if (!is_elf_hash_table (info->hash))
- return FALSE;
-
- for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
- if ((ibfd->flags & DYNAMIC) == 0)
- for (sec = ibfd->sections; sec != NULL; sec = sec->next)
- if ((sec->flags & SEC_MERGE) != 0
- && !bfd_is_abs_section (sec->output_section))
- {
- struct bfd_elf_section_data *secdata;
-
- secdata = elf_section_data (sec);
- if (! _bfd_add_merge_section (abfd,
- &elf_hash_table (info)->merge_info,
- sec, &secdata->sec_info))
- return FALSE;
- else if (secdata->sec_info)
- sec->sec_info_type = ELF_INFO_TYPE_MERGE;
- }
-
- if (elf_hash_table (info)->merge_info != NULL)
- _bfd_merge_sections (abfd, info, elf_hash_table (info)->merge_info,
- merge_sections_remove_hook);
- return TRUE;
-}
-
-void
-_bfd_elf_link_just_syms (asection *sec, struct bfd_link_info *info)
-{
- sec->output_section = bfd_abs_section_ptr;
- sec->output_offset = sec->vma;
- if (!is_elf_hash_table (info->hash))
- return;
-
- sec->sec_info_type = ELF_INFO_TYPE_JUST_SYMS;
-}
-\f
/* Copy the program header and other data from one object module to
another. */
elf_gp (obfd) = elf_gp (ibfd);
elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
elf_flags_init (obfd) = TRUE;
+
+ /* Copy object attributes. */
+ _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
return TRUE;
}
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);
we've already printed the size; now print the alignment.
For other symbols, we have no specified alignment, and
we've printed the address; now print the size. */
- if (bfd_is_com_section (symbol->section))
+ if (symbol->section && bfd_is_com_section (symbol->section))
val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_value;
else
val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_size;
break;
}
}
-\f
-/* Create an entry in an ELF linker hash table. */
-
-struct bfd_hash_entry *
-_bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
- struct bfd_hash_table *table,
- const char *string)
-{
- /* Allocate the structure if it has not already been allocated by a
- subclass. */
- if (entry == NULL)
- {
- entry = bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry));
- if (entry == NULL)
- return entry;
- }
-
- /* Call the allocation method of the superclass. */
- entry = _bfd_link_hash_newfunc (entry, table, string);
- if (entry != NULL)
- {
- struct elf_link_hash_entry *ret = (struct elf_link_hash_entry *) entry;
- struct elf_link_hash_table *htab = (struct elf_link_hash_table *) table;
-
- /* Set local fields. */
- ret->indx = -1;
- ret->dynindx = -1;
- ret->got = htab->init_got_refcount;
- ret->plt = htab->init_plt_refcount;
- memset (&ret->size, 0, (sizeof (struct elf_link_hash_entry)
- - offsetof (struct elf_link_hash_entry, size)));
- /* Assume that we have been called by a non-ELF symbol reader.
- This flag is then reset by the code which reads an ELF input
- file. This ensures that a symbol created by a non-ELF symbol
- reader will have the flag set correctly. */
- ret->non_elf = 1;
- }
-
- return entry;
-}
-
-/* Copy data from an indirect symbol to its direct symbol, hiding the
- old indirect symbol. Also used for copying flags to a weakdef. */
-
-void
-_bfd_elf_link_hash_copy_indirect (struct bfd_link_info *info,
- struct elf_link_hash_entry *dir,
- struct elf_link_hash_entry *ind)
-{
- struct elf_link_hash_table *htab;
-
- /* Copy down any references that we may have already seen to the
- symbol which just became indirect. */
-
- dir->ref_dynamic |= ind->ref_dynamic;
- dir->ref_regular |= ind->ref_regular;
- dir->ref_regular_nonweak |= ind->ref_regular_nonweak;
- dir->non_got_ref |= ind->non_got_ref;
- dir->needs_plt |= ind->needs_plt;
- dir->pointer_equality_needed |= ind->pointer_equality_needed;
-
- if (ind->root.type != bfd_link_hash_indirect)
- return;
-
- /* Copy over the global and procedure linkage table refcount entries.
- These may have been already set up by a check_relocs routine. */
- htab = elf_hash_table (info);
- if (ind->got.refcount > htab->init_got_refcount.refcount)
- {
- if (dir->got.refcount < 0)
- dir->got.refcount = 0;
- dir->got.refcount += ind->got.refcount;
- ind->got.refcount = htab->init_got_refcount.refcount;
- }
-
- if (ind->plt.refcount > htab->init_plt_refcount.refcount)
- {
- if (dir->plt.refcount < 0)
- dir->plt.refcount = 0;
- dir->plt.refcount += ind->plt.refcount;
- ind->plt.refcount = htab->init_plt_refcount.refcount;
- }
-
- if (ind->dynindx != -1)
- {
- if (dir->dynindx != -1)
- _bfd_elf_strtab_delref (htab->dynstr, dir->dynstr_index);
- dir->dynindx = ind->dynindx;
- dir->dynstr_index = ind->dynstr_index;
- ind->dynindx = -1;
- ind->dynstr_index = 0;
- }
-}
-
-void
-_bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info,
- struct elf_link_hash_entry *h,
- bfd_boolean force_local)
-{
- h->plt = elf_hash_table (info)->init_plt_offset;
- h->needs_plt = 0;
- if (force_local)
- {
- h->forced_local = 1;
- if (h->dynindx != -1)
- {
- h->dynindx = -1;
- _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
- h->dynstr_index);
- }
- }
-}
-
-/* Initialize an ELF linker hash table. */
-
-bfd_boolean
-_bfd_elf_link_hash_table_init
- (struct elf_link_hash_table *table,
- bfd *abfd,
- struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
- struct bfd_hash_table *,
- const char *),
- unsigned int entsize)
-{
- bfd_boolean ret;
- int can_refcount = get_elf_backend_data (abfd)->can_refcount;
-
- table->dynamic_sections_created = FALSE;
- table->dynobj = NULL;
- 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;
-
- return ret;
-}
-
-/* Create an ELF linker hash table. */
-
-struct bfd_link_hash_table *
-_bfd_elf_link_hash_table_create (bfd *abfd)
-{
- struct elf_link_hash_table *ret;
- bfd_size_type amt = sizeof (struct elf_link_hash_table);
-
- ret = bfd_malloc (amt);
- if (ret == NULL)
- return NULL;
-
- if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc,
- sizeof (struct elf_link_hash_entry)))
- {
- free (ret);
- return NULL;
- }
-
- return &ret->root;
-}
-/* This is a hook for the ELF emulation code in the generic linker to
- tell the backend linker what file name to use for the DT_NEEDED
- entry for a dynamic object. */
-
-void
-bfd_elf_set_dt_needed_name (bfd *abfd, const char *name)
-{
- if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
- && bfd_get_format (abfd) == bfd_object)
- elf_dt_name (abfd) = name;
-}
-
-int
-bfd_elf_get_dyn_lib_class (bfd *abfd)
-{
- int lib_class;
- if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
- && bfd_get_format (abfd) == bfd_object)
- lib_class = elf_dyn_lib_class (abfd);
- else
- lib_class = 0;
- return lib_class;
-}
-
-void
-bfd_elf_set_dyn_lib_class (bfd *abfd, int lib_class)
-{
- if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
- && bfd_get_format (abfd) == bfd_object)
- elf_dyn_lib_class (abfd) = lib_class;
-}
-
-/* Get the list of DT_NEEDED entries for a link. This is a hook for
- the linker ELF emulation code. */
-
-struct bfd_link_needed_list *
-bfd_elf_get_needed_list (bfd *abfd ATTRIBUTE_UNUSED,
- struct bfd_link_info *info)
-{
- if (! is_elf_hash_table (info->hash))
- return NULL;
- return elf_hash_table (info)->needed;
-}
-
-/* Get the list of DT_RPATH/DT_RUNPATH entries for a link. This is a
- hook for the linker ELF emulation code. */
-
-struct bfd_link_needed_list *
-bfd_elf_get_runpath_list (bfd *abfd ATTRIBUTE_UNUSED,
- struct bfd_link_info *info)
-{
- if (! is_elf_hash_table (info->hash))
- return NULL;
- return elf_hash_table (info)->runpath;
-}
-
-/* Get the name actually used for a dynamic object for a link. This
- is the SONAME entry if there is one. Otherwise, it is the string
- passed to bfd_elf_set_dt_needed_name, or it is the filename. */
-
-const char *
-bfd_elf_get_dt_soname (bfd *abfd)
-{
- if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
- && bfd_get_format (abfd) == bfd_object)
- return elf_dt_name (abfd);
- return NULL;
-}
-
-/* Get the list of DT_NEEDED entries from a BFD. This is a hook for
- the ELF linker emulation code. */
-
-bfd_boolean
-bfd_elf_get_bfd_needed_list (bfd *abfd,
- struct bfd_link_needed_list **pneeded)
-{
- asection *s;
- bfd_byte *dynbuf = NULL;
- int elfsec;
- unsigned long shlink;
- bfd_byte *extdyn, *extdynend;
- size_t extdynsize;
- void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
-
- *pneeded = NULL;
-
- if (bfd_get_flavour (abfd) != bfd_target_elf_flavour
- || bfd_get_format (abfd) != bfd_object)
- return TRUE;
-
- s = bfd_get_section_by_name (abfd, ".dynamic");
- if (s == NULL || s->size == 0)
- return TRUE;
-
- if (!bfd_malloc_and_get_section (abfd, s, &dynbuf))
- goto error_return;
-
- elfsec = _bfd_elf_section_from_bfd_section (abfd, s);
- if (elfsec == -1)
- goto error_return;
-
- shlink = elf_elfsections (abfd)[elfsec]->sh_link;
-
- extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
- swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
-
- extdyn = dynbuf;
- extdynend = extdyn + s->size;
- for (; extdyn < extdynend; extdyn += extdynsize)
- {
- Elf_Internal_Dyn dyn;
-
- (*swap_dyn_in) (abfd, extdyn, &dyn);
-
- if (dyn.d_tag == DT_NULL)
- break;
-
- if (dyn.d_tag == DT_NEEDED)
- {
- const char *string;
- struct bfd_link_needed_list *l;
- unsigned int tagv = dyn.d_un.d_val;
- bfd_size_type amt;
-
- string = bfd_elf_string_from_elf_section (abfd, shlink, tagv);
- if (string == NULL)
- goto error_return;
-
- amt = sizeof *l;
- l = bfd_alloc (abfd, amt);
- if (l == NULL)
- goto error_return;
-
- l->by = abfd;
- l->name = string;
- l->next = *pneeded;
- *pneeded = l;
- }
- }
-
- free (dynbuf);
-
- return TRUE;
-
- error_return:
- if (dynbuf != NULL)
- free (dynbuf);
- return FALSE;
-}
-\f
/* Allocate an ELF string table--force the first byte to be zero. */
struct bfd_strtab_hash *
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_SYMS;
/* Sometimes a shared object will map in the symbol table. If
- SHF_ALLOC is set, and this is a shared object, then we also
- treat this section as a BFD section. We can not base the
- decision purely on SHF_ALLOC, because that flag is sometimes
- set in a relocatable object file, which would confuse the
- linker. */
+ SHF_ALLOC is set, and this is a shared object, then we also
+ treat this section as a BFD section. We can not base the
+ decision purely on SHF_ALLOC, because that flag is sometimes
+ set in a relocatable object file, which would confuse the
+ linker. */
if ((hdr->sh_flags & SHF_ALLOC) != 0
&& (abfd->flags & DYNAMIC) != 0
&& ! _bfd_elf_make_section_from_shdr (abfd, hdr, name,
BFD_ASSERT (elf_section_data (target_sect)->rel_hdr2 == NULL);
amt = sizeof (*hdr2);
hdr2 = bfd_alloc (abfd, amt);
+ if (hdr2 == NULL)
+ return FALSE;
elf_section_data (target_sect)->rel_hdr2 = hdr2;
}
*hdr2 = *hdr;
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;
default:
+ /* Possibly an attributes section. */
+ if (hdr->sh_type == SHT_GNU_ATTRIBUTES
+ || hdr->sh_type == bed->obj_attrs_section_type)
+ {
+ if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
+ return FALSE;
+ _bfd_elf_parse_attributes (abfd, hdr);
+ return TRUE;
+ }
+
/* Check for any processor-specific section types. */
if (bed->elf_backend_section_from_shdr (abfd, hdr, name, shindex))
return TRUE;
"`%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)
asection *sec,
unsigned long r_symndx)
{
- Elf_Internal_Shdr *symtab_hdr;
- unsigned char esym[sizeof (Elf64_External_Sym)];
- Elf_External_Sym_Shndx eshndx;
- Elf_Internal_Sym isym;
unsigned int ent = r_symndx % LOCAL_SYM_CACHE_SIZE;
+ asection *s;
- if (cache->abfd == abfd && cache->indx[ent] == r_symndx)
- return cache->sec[ent];
+ if (cache->abfd != abfd || cache->indx[ent] != r_symndx)
+ {
+ Elf_Internal_Shdr *symtab_hdr;
+ unsigned char esym[sizeof (Elf64_External_Sym)];
+ Elf_External_Sym_Shndx eshndx;
+ Elf_Internal_Sym isym;
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- if (bfd_elf_get_elf_syms (abfd, symtab_hdr, 1, r_symndx,
- &isym, esym, &eshndx) == NULL)
- return NULL;
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ if (bfd_elf_get_elf_syms (abfd, symtab_hdr, 1, r_symndx,
+ &isym, esym, &eshndx) == NULL)
+ return NULL;
- if (cache->abfd != abfd)
- {
- memset (cache->indx, -1, sizeof (cache->indx));
- cache->abfd = abfd;
- }
- cache->indx[ent] = r_symndx;
- cache->sec[ent] = sec;
- if ((isym.st_shndx != SHN_UNDEF && isym.st_shndx < SHN_LORESERVE)
- || isym.st_shndx > SHN_HIRESERVE)
- {
- asection *s;
- s = bfd_section_from_elf_index (abfd, isym.st_shndx);
- if (s != NULL)
- cache->sec[ent] = s;
+ if (cache->abfd != abfd)
+ {
+ memset (cache->indx, -1, sizeof (cache->indx));
+ cache->abfd = abfd;
+ }
+ cache->indx[ent] = r_symndx;
+ cache->shndx[ent] = isym.st_shndx;
}
- return cache->sec[ent];
+
+ s = bfd_section_from_elf_index (abfd, cache->shndx[ent]);
+ if (s != NULL)
+ return s;
+
+ return sec;
}
/* Given an ELF section number, retrieve the corresponding BFD
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[] =
{
special_sections_b, /* 'b' */
- special_sections_c, /* 'b' */
+ special_sections_c, /* 'c' */
special_sections_d, /* 'd' */
NULL, /* 'e' */
special_sections_f, /* 'f' */
for the single program segment. The first has the length specified by
the file size of the segment, and the second has the length specified
by the difference between the two sizes. In effect, the segment is split
- into it's initialized and uninitialized parts.
+ into its initialized and uninitialized parts.
*/
split = ((hdr->p_memsz > 0)
&& (hdr->p_filesz > 0)
&& (hdr->p_memsz > hdr->p_filesz));
- sprintf (namebuf, "%s%d%s", typename, index, split ? "a" : "");
- len = strlen (namebuf) + 1;
- name = bfd_alloc (abfd, len);
- if (!name)
- return FALSE;
- memcpy (name, namebuf, len);
- newsect = bfd_make_section (abfd, name);
- if (newsect == NULL)
- return FALSE;
- newsect->vma = hdr->p_vaddr;
- newsect->lma = hdr->p_paddr;
- newsect->size = hdr->p_filesz;
- newsect->filepos = hdr->p_offset;
- newsect->flags |= SEC_HAS_CONTENTS;
- newsect->alignment_power = bfd_log2 (hdr->p_align);
- if (hdr->p_type == PT_LOAD)
- {
- newsect->flags |= SEC_ALLOC;
- newsect->flags |= SEC_LOAD;
- if (hdr->p_flags & PF_X)
- {
- /* FIXME: all we known is that it has execute PERMISSION,
- may be data. */
- newsect->flags |= SEC_CODE;
- }
- }
- if (!(hdr->p_flags & PF_W))
- {
- newsect->flags |= SEC_READONLY;
- }
- if (split)
+ if (hdr->p_filesz > 0)
{
- sprintf (namebuf, "%s%db", typename, index);
+ sprintf (namebuf, "%s%d%s", typename, index, split ? "a" : "");
len = strlen (namebuf) + 1;
name = bfd_alloc (abfd, len);
if (!name)
newsect = bfd_make_section (abfd, name);
if (newsect == NULL)
return FALSE;
- newsect->vma = hdr->p_vaddr + hdr->p_filesz;
- newsect->lma = hdr->p_paddr + hdr->p_filesz;
- newsect->size = hdr->p_memsz - hdr->p_filesz;
+ newsect->vma = hdr->p_vaddr;
+ newsect->lma = hdr->p_paddr;
+ newsect->size = hdr->p_filesz;
+ newsect->filepos = hdr->p_offset;
+ newsect->flags |= SEC_HAS_CONTENTS;
+ newsect->alignment_power = bfd_log2 (hdr->p_align);
if (hdr->p_type == PT_LOAD)
{
newsect->flags |= SEC_ALLOC;
+ newsect->flags |= SEC_LOAD;
if (hdr->p_flags & PF_X)
- newsect->flags |= SEC_CODE;
+ {
+ /* FIXME: all we known is that it has execute PERMISSION,
+ may be data. */
+ newsect->flags |= SEC_CODE;
+ }
+ }
+ if (!(hdr->p_flags & PF_W))
+ {
+ newsect->flags |= SEC_READONLY;
+ }
+ }
+
+ if (hdr->p_memsz > hdr->p_filesz)
+ {
+ bfd_vma align;
+
+ sprintf (namebuf, "%s%d%s", typename, index, split ? "b" : "");
+ len = strlen (namebuf) + 1;
+ name = bfd_alloc (abfd, len);
+ if (!name)
+ return FALSE;
+ memcpy (name, namebuf, len);
+ newsect = bfd_make_section (abfd, name);
+ if (newsect == NULL)
+ return FALSE;
+ newsect->vma = hdr->p_vaddr + hdr->p_filesz;
+ newsect->lma = hdr->p_paddr + hdr->p_filesz;
+ newsect->size = hdr->p_memsz - hdr->p_filesz;
+ newsect->filepos = hdr->p_offset + hdr->p_filesz;
+ align = newsect->vma & -newsect->vma;
+ if (align == 0 || align > hdr->p_align)
+ align = hdr->p_align;
+ newsect->alignment_power = bfd_log2 (align);
+ if (hdr->p_type == PT_LOAD)
+ {
+ /* Hack for gdb. Segments that have not been modified do
+ not have their contents written to a core file, on the
+ assumption that a debugger can find the contents in the
+ executable. We flag this case by setting the fake
+ section size to zero. Note that "real" bss sections will
+ always have their contents dumped to the core file. */
+ if (bfd_get_format (abfd) == bfd_core)
+ newsect->size = 0;
+ newsect->flags |= SEC_ALLOC;
+ if (hdr->p_flags & PF_X)
+ newsect->flags |= SEC_CODE;
}
if (!(hdr->p_flags & PF_W))
newsect->flags |= SEC_READONLY;
case PT_NOTE:
if (! _bfd_elf_make_section_from_phdr (abfd, hdr, index, "note"))
return FALSE;
- if (! elfcore_read_notes (abfd, hdr->p_offset, hdr->p_filesz))
+ if (! elf_read_notes (abfd, hdr->p_offset, hdr->p_filesz))
return FALSE;
return TRUE;
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)
{
/* We already failed; just get out of the bfd_map_over_sections
- loop. */
+ loop. */
return;
}
/* If the section type is unspecified, we set it based on
asect->flags. */
+ if ((asect->flags & SEC_GROUP) != 0)
+ sh_type = SHT_GROUP;
+ else if ((asect->flags & SEC_ALLOC) != 0
+ && (((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
+ || (asect->flags & SEC_NEVER_LOAD) != 0))
+ sh_type = SHT_NOBITS;
+ else
+ sh_type = SHT_PROGBITS;
+
if (this_hdr->sh_type == SHT_NULL)
- {
- if ((asect->flags & SEC_GROUP) != 0)
- this_hdr->sh_type = SHT_GROUP;
- else if ((asect->flags & SEC_ALLOC) != 0
- && (((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0)
- || (asect->flags & SEC_NEVER_LOAD) != 0))
- this_hdr->sh_type = SHT_NOBITS;
- else
- this_hdr->sh_type = SHT_PROGBITS;
+ this_hdr->sh_type = sh_type;
+ else if (this_hdr->sh_type == SHT_NOBITS
+ && sh_type == SHT_PROGBITS
+ && (asect->flags & SEC_ALLOC) != 0)
+ {
+ /* Warn if we are changing a NOBITS section to PROGBITS, but
+ allow the link to proceed. This can happen when users link
+ non-bss input sections to bss output sections, or emit data
+ to a bss output section via a linker script. */
+ (*_bfd_error_handler)
+ (_("warning: section `%A' type changed to PROGBITS"), asect);
+ this_hdr->sh_type = sh_type;
}
switch (this_hdr->sh_type)
case SHT_GNU_verdef:
this_hdr->sh_entsize = 0;
/* objcopy or strip will copy over sh_info, but may not set
- cverdefs. The linker will set cverdefs, but sh_info will be
- zero. */
+ cverdefs. The linker will set cverdefs, but sh_info will be
+ zero. */
if (this_hdr->sh_info == 0)
this_hdr->sh_info = elf_tdata (abfd)->cverdefs;
else
case SHT_GNU_verneed:
this_hdr->sh_entsize = 0;
/* objcopy or strip will copy over sh_info, but may not set
- cverrefs. The linker will set cverrefs, but sh_info will be
- zero. */
+ cverrefs. The linker will set cverrefs, but sh_info will be
+ zero. */
if (this_hdr->sh_info == 0)
this_hdr->sh_info = elf_tdata (abfd)->cverrefs;
else
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
d = elf_section_data (sec);
if (d->this_hdr.sh_type == SHT_GROUP)
- {
+ {
if (sec->flags & SEC_LINKER_CREATED)
{
/* Remove the linker created SHT_GROUP sections. */
bfd_section_list_remove (abfd, sec);
abfd->section_count--;
}
- else
+ else
{
if (section_number == SHN_LORESERVE)
section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE;
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);
The Intel C compiler generates SHT_IA_64_UNWIND with
SHF_LINK_ORDER. But it doesn't set the sh_link or
sh_info fields. Hence we could get the situation
- where s is NULL. */
+ where s is NULL. */
const struct elf_backend_data *bed
= get_elf_backend_data (abfd);
if (bed->link_order_error_handler)
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;
case SHT_GNU_LIBLIST:
/* sh_link is the section header index of the prelink library
- list
- used for the dynamic entries, or the symbol table, or the
- version strings. */
+ list used for the dynamic entries, or the symbol table, or
+ the version strings. */
s = bfd_get_section_by_name (abfd, (sec->flags & SEC_ALLOC)
? ".dynstr" : ".gnu.libstr");
if (s != NULL)
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. */
elf_tdata (abfd)->next_file_pos = off;
/* Now that we know where the .strtab section goes, write it
- out. */
+ out. */
if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
|| ! _bfd_stringtab_emit (abfd, strtab))
return FALSE;
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 (info->relro)
+ {
+ /* We need a PT_GNU_RELRO 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;
+ /* Try to create just one PT_NOTE segment
+ for all adjacent loadable .note* sections.
+ gABI requires that within a PT_NOTE segment
+ (and also inside of each SHT_NOTE section)
+ each note is padded to a multiple of 4 size,
+ so we check whether the sections are correctly
+ aligned. */
+ if (s->alignment_power == 2)
+ while (s->next != NULL
+ && s->next->alignment_power == 2
+ && (s->next->flags & SEC_LOAD) != 0
+ && CONST_STRNEQ (s->next->name, ".note"))
+ s = s->next;
+ }
+ }
+
+ 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;
+}
+
+/* Find the segment that contains the output_section of section. */
+
+Elf_Internal_Phdr *
+_bfd_elf_find_segment_containing_section (bfd * abfd, asection * section)
+{
+ struct elf_segment_map *m;
+ Elf_Internal_Phdr *p;
+
+ for (m = elf_tdata (abfd)->segment_map,
+ p = elf_tdata (abfd)->phdr;
+ m != NULL;
+ m = m->next, p++)
+ {
+ int i;
+
+ for (i = m->count - 1; i >= 0; i--)
+ if (m->sections[i] == section)
+ return p;
+ }
+
+ return NULL;
+}
+
/* Create a mapping from a set of sections to a program segment. */
static struct elf_segment_map *
m->p_type = PT_DYNAMIC;
m->count = 1;
m->sections[0] = dynsec;
-
+
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,
+ bfd_boolean remove_empty_load)
{
- 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 (remove_empty_load && (*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);
+ bfd_boolean no_user_phdrs;
- /* 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)
+ no_user_phdrs = elf_tdata (abfd)->segment_map == NULL;
+ if (no_user_phdrs && 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))
- {
- /* 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)
+ i = 0;
+ for (s = abfd->sections; s != NULL; s = s->next)
{
- 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;
+ if ((s->flags & SEC_ALLOC) != 0)
+ {
+ sections[i] = s;
+ ++i;
+ }
}
+ BFD_ASSERT (i <= bfd_count_sections (abfd));
+ count = i;
- /* 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;
+ qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections);
- 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;
- }
+ /* Build the mapping. */
- /* 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;
+ mfirst = NULL;
+ pm = &mfirst;
- *pm = m;
- pm = &m->next;
- }
+ /* 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)
+ {
+ 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;
- /* 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)
- {
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_INTERP;
m->count = 1;
m->sections[0] = s;
*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)
+ /* 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)
{
- BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL);
- m->sections[i] = first_tls;
- first_tls = first_tls->next;
+ 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;
}
- *pm = m;
- pm = &m->next;
- }
-
- /* 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;
- }
+ for (i = 0, hdrpp = sections; i < count; i++, hdrpp++)
+ {
+ asection *hdr;
+ bfd_boolean new_segment;
- 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;
+ hdr = *hdrpp;
- *pm = m;
- pm = &m->next;
- }
+ /* See if this section and the last one will fit in the same
+ segment. */
- 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;
+ 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;
+ phdr_index = i;
+ phdr_in_segment = FALSE;
+ }
+
+ /* 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;
+
+ *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;
+ }
+
+ /* For each batch of consecutive loadable .note sections,
+ 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"))
+ {
+ asection *s2;
+ unsigned count = 1;
+ amt = sizeof (struct elf_segment_map);
+ if (s->alignment_power == 2)
+ for (s2 = s; s2->next != NULL; s2 = s2->next)
+ {
+ if (s2->next->alignment_power == 2
+ && (s2->next->flags & SEC_LOAD) != 0
+ && CONST_STRNEQ (s2->next->name, ".note")
+ && align_power (s2->vma + s2->size, 2)
+ == s2->next->vma)
+ count++;
+ else
+ break;
+ }
+ amt += (count - 1) * sizeof (asection *);
+ m = bfd_zalloc (abfd, amt);
+ if (m == NULL)
+ goto error_return;
+ m->next = NULL;
+ m->p_type = PT_NOTE;
+ m->count = count;
+ while (count > 1)
+ {
+ m->sections[m->count - count--] = s;
+ BFD_ASSERT ((s->flags & SEC_THREAD_LOCAL) == 0);
+ s = s->next;
+ }
+ m->sections[m->count - 1] = s;
+ BFD_ASSERT ((s->flags & SEC_THREAD_LOCAL) == 0);
+ *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)
+ {
+ BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL);
+ m->sections[i] = first_tls;
+ first_tls = first_tls->next;
+ }
+
+ *pm = m;
+ pm = &m->next;
+ }
+
+ /* 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;
+ }
+
+ 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;
+ }
+
+ if (info->relro)
+ {
+ for (m = mfirst; m != NULL; m = m->next)
+ {
+ if (m->p_type == PT_LOAD)
+ {
+ asection *last = m->sections[m->count - 1];
+ bfd_vma vaddr = m->sections[0]->vma;
+ bfd_vma filesz = last->vma - vaddr + last->size;
+
+ if (vaddr < info->relro_end
+ && vaddr >= info->relro_start
+ && (vaddr + filesz) >= info->relro_end)
+ break;
+ }
+ }
- *pm = m;
- pm = &m->next;
+ /* Make a PT_GNU_RELRO segment only when it isn't empty. */
+ if (m != NULL)
+ {
+ 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;
+ }
+ }
+
+ free (sections);
+ elf_tdata (abfd)->segment_map = mfirst;
}
- free (sections);
- sections = NULL;
+ if (!elf_modify_segment_map (abfd, info, no_user_phdrs))
+ return FALSE;
+
+ 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:
adjustment = vma_offset + bed->maxpagesize - off_offset;
else
adjustment = vma_offset - off_offset;
-
+
which can can be collapsed into the expression below. */
static file_ptr
}
static void
-print_segment_map (bfd *abfd)
+print_segment_map (const struct elf_segment_map *m)
{
- struct elf_segment_map *m;
- unsigned int i, j;
-
- fprintf (stderr, _(" Section to Segment mapping:\n"));
- fprintf (stderr, _(" Segment Sections...\n"));
+ unsigned int j;
+ const char *pt = get_segment_type (m->p_type);
+ char buf[32];
- for (i= 0, m = elf_tdata (abfd)->segment_map;
- m != NULL;
- i++, m = m->next)
+ if (pt == NULL)
{
- 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);
+ 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, "%s:", 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
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, FALSE))
+ 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;
+ bfd_vma off_adjust;
+ bfd_boolean no_contents;
/* If elf_segment_map is not from map_sections_to_segments, the
- sections may not be correctly ordered. NOTE: sorting should
+ sections may not be correctly ordered. NOTE: sorting should
not be done to the PT_NOTE section of a corefile, which may
contain several pseudo-sections artificially created by bfd.
Sorting these pseudo-sections breaks things badly. */
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_paddr = 0;
else
- p->p_paddr = m->sections[0]->lma;
+ p->p_paddr = m->sections[0]->lma - m->p_vaddr_offset;
if (p->p_type == PT_LOAD
&& (abfd->flags & D_PAGED) != 0)
p->p_align = maxpagesize;
}
+ else if (m->p_align_valid)
+ p->p_align = m->p_align;
else if (m->count == 0)
p->p_align = 1 << bed->s->log_file_align;
else
p->p_align = 0;
+ no_contents = FALSE;
+ off_adjust = 0;
if (p->p_type == PT_LOAD
&& m->count > 0)
{
bfd_size_type align;
- 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;
+ 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;
+ 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;
- 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)
+ 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;
+
+ /* Find out whether this segment contains any loadable
+ sections. If the first section isn't loadable, the same
+ holds for any other sections. */
+ i = 0;
+ while (elf_section_type (m->sections[i]) == SHT_NOBITS)
{
- /* 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. */
- i = 0;
- while ((m->sections[i]->flags & SEC_LOAD) == 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)
{
- if ((m->sections[i]->flags & SEC_THREAD_LOCAL) == 0
- || ++i >= m->count)
- {
- off -= adjust;
- voff = adjust - align;
- break;
- }
+ no_contents = TRUE;
+ break;
}
}
+
+ off_adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align);
+ off += off_adjust;
+ if (no_contents)
+ {
+ /* We shouldn't need to align the segment on disk since
+ the segment doesn't need file space, but the gABI
+ arguably requires the alignment and glibc ld.so
+ checks it. So to comply with the alignment
+ requirement but not waste file space, we adjust
+ p_offset for just this segment. (OFF_ADJUST is
+ subtracted from OFF later.) This may put p_offset
+ past the end of file, but that shouldn't matter. */
+ }
+ else
+ off_adjust = 0;
}
/* Make sure the .dynamic section is the first section in the
PT_DYNAMIC segment. */
if (m->includes_filehdr)
{
- if (! m->p_flags_valid)
+ 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_vaddr -= off;
- if (! m->p_paddr_valid)
+ if (!m->p_paddr_valid)
p->p_paddr -= off;
}
}
if (m->includes_phdrs)
{
- if (! m->p_flags_valid)
+ if (!m->p_flags_valid)
p->p_flags |= PF_R;
if (!m->includes_filehdr)
{
BFD_ASSERT (p->p_type == PT_LOAD);
p->p_vaddr -= off - p->p_offset;
- if (! m->p_paddr_valid)
+ if (!m->p_paddr_valid)
p->p_paddr -= off - p->p_offset;
}
}
if (p->p_type == PT_LOAD
|| (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core))
{
- if (! m->includes_filehdr && ! m->includes_phdrs)
- p->p_offset = off + voff;
+ if (!m->includes_filehdr && !m->includes_phdrs)
+ p->p_offset = off;
else
{
file_ptr adjust;
adjust = off - (p->p_offset + p->p_filesz);
- p->p_filesz += adjust;
+ if (!no_contents)
+ p->p_filesz += adjust;
p->p_memsz += 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;
- off += sec->size;
- p->p_filesz = sec->size;
+ this_hdr->sh_offset = sec->filepos = off;
+ off += this_hdr->sh_size;
+ p->p_filesz = this_hdr->sh_size;
p->p_memsz = 0;
p->p_align = 1;
}
{
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)
- off += sec->size;
+ this_hdr->sh_offset = sec->filepos = off;
+ if (this_hdr->sh_type != SHT_NOBITS)
+ off += this_hdr->sh_size;
}
- if ((flags & SEC_LOAD) != 0)
+ if (this_hdr->sh_type != SHT_NOBITS)
{
- p->p_filesz += sec->size;
- p->p_memsz += sec->size;
+ p->p_filesz += this_hdr->sh_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 += this_hdr->sh_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
- || p->p_type == PT_TLS))
- p->p_memsz += sec->size;
-
- if (p->p_type == PT_TLS
- && sec->size == 0
- && (sec->flags & SEC_HAS_CONTENTS) == 0)
+ else if ((this_hdr->sh_flags & SHF_ALLOC) != 0)
{
- struct bfd_link_order *o = sec->map_tail.link_order;
- if (o != NULL)
- p->p_memsz += o->offset + o->size;
+ if (p->p_type == PT_TLS)
+ p->p_memsz += this_hdr->sh_size;
+
+ /* .tbss is special. It doesn't contribute to p_memsz of
+ normal segments. */
+ else if ((this_hdr->sh_flags & SHF_TLS) == 0)
+ p->p_memsz += this_hdr->sh_size;
}
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)
+ 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;
}
}
- }
+ off -= off_adjust;
- /* 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);
+ print_segment_map (m);
+ 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->count != 0)
{
if (p->p_type != PT_LOAD
- && (p->p_type != PT_NOTE || bfd_get_format (abfd) != bfd_core))
+ && (p->p_type != PT_NOTE
+ || bfd_get_format (abfd) != bfd_core))
{
Elf_Internal_Shdr *hdr;
+ asection *sect;
+
BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs);
- hdr = &elf_section_data (m->sections[m->count - 1])->this_hdr;
- p->p_filesz = (m->sections[m->count - 1]->filepos
- - m->sections[0]->filepos);
+ sect = m->sections[m->count - 1];
+ hdr = &elf_section_data (sect)->this_hdr;
+ p->p_filesz = sect->filepos - m->sections[0]->filepos;
if (hdr->sh_type != SHT_NOBITS)
p->p_filesz += hdr->sh_size;
- p->p_offset = m->sections[0]->filepos;
+ if (p->p_type == PT_GNU_RELRO)
+ {
+ /* When we get here, we are copying executable
+ or shared library. But we need to use the same
+ linker logic. */
+ Elf_Internal_Phdr *lp;
+
+ for (lp = phdrs; lp < phdrs + count; ++lp)
+ {
+ if (lp->p_type == PT_LOAD
+ && lp->p_paddr == p->p_paddr)
+ break;
+ }
+
+ if (lp < phdrs + count)
+ {
+ /* We should use p_size if it is valid since it
+ may contain the first few bytes of the next
+ SEC_ALLOC section. */
+ if (m->p_size_valid)
+ p->p_filesz = m->p_size;
+ else
+ abort ();
+ p->p_vaddr = lp->p_vaddr;
+ p->p_offset = lp->p_offset;
+ p->p_memsz = p->p_filesz;
+ p->p_align = 1;
+ }
+ else
+ abort ();
+ }
+ else
+ p->p_offset = m->sections[0]->filepos;
}
}
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)
-{
- 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);
- 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.
unsigned int alloc;
/* Assign file positions for the loaded sections based on the
- assignment of sections to segments. */
+ assignment of sections to segments. */
if (!assign_file_positions_for_load_sections (abfd, link_info))
return FALSE;
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
/* Write out the section header names. */
if (elf_shstrtab (abfd) != NULL
&& (bfd_seek (abfd, elf_tdata (abfd)->shstrtab_hdr.sh_offset, SEEK_SET) != 0
- || ! _bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd))))
+ || !_bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd))))
return FALSE;
if (bed->elf_backend_final_write_processing)
(*bed->elf_backend_final_write_processing) (abfd,
elf_tdata (abfd)->linker);
- return bed->s->write_shdrs_and_ehdr (abfd);
+ if (!bed->s->write_shdrs_and_ehdr (abfd))
+ return FALSE;
+
+ /* This is last since write_shdrs_and_ehdr can touch i_shdrp[0]. */
+ if (elf_tdata (abfd)->after_write_object_contents)
+ return (*elf_tdata (abfd)->after_write_object_contents) (abfd);
+
+ return TRUE;
}
bfd_boolean
if (idx == 0)
{
/* This case can occur when using --strip-symbol on a symbol
- which is used in a relocation entry. */
+ which is used in a relocation entry. */
(*_bfd_error_handler)
(_("%B: symbol `%s' required but not present"),
abfd, bfd_asymbol_name (asym_ptr));
&& (section->lma + SECTION_SIZE (section, segment) \
<= SEGMENT_END (segment, base)))
- /* Special case: corefile "NOTE" section containing regs, prpsinfo etc. */
-#define IS_COREFILE_NOTE(p, s) \
+ /* Handle PT_NOTE segment. */
+#define IS_NOTE(p, s) \
(p->p_type == PT_NOTE \
- && bfd_get_format (ibfd) == bfd_core \
- && s->vma == 0 && s->lma == 0 \
+ && elf_section_type (s) == SHT_NOTE \
&& (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))
+ /* Special case: corefile "NOTE" section containing regs, prpsinfo
+ etc. */
+#define IS_COREFILE_NOTE(p, s) \
+ (IS_NOTE (p, s) \
+ && bfd_get_format (ibfd) == bfd_core \
+ && s->vma == 0 \
+ && s->lma == 0)
+
/* The complicated case when p_vaddr is 0 is to handle the Solaris
linker, which generates a PT_INTERP section with p_vaddr and
p_memsz set to 0. */
&& (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.
A section will be included if:
1. It is within the address space of the segment -- we use the LMA
- if that is set for the segment and the VMA otherwise,
- 2. It is an allocated segment,
+ if that is set for the segment and the VMA otherwise,
+ 2. It is an allocated section or a NOTE section in a PT_NOTE
+ segment.
3. There is an output section associated with it,
4. The section has not already been allocated to a previous segment.
5. PT_GNU_STACK segments do not include any sections.
6. PT_TLS segment includes only SHF_TLS sections.
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) \
+ (with the possible exception of .dynamic). */
+#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 \
+ || IS_NOTE (segment, section)) \
&& segment->p_type != PT_GNU_STACK \
&& (segment->p_type != PT_TLS \
|| (section->flags & SEC_THREAD_LOCAL)) \
&& (segment->p_type != PT_DYNAMIC \
|| SECTION_SIZE (section, segment) > 0 \
|| (segment->p_paddr \
- ? segment->p_paddr != section->lma \
- : segment->p_vaddr != section->vma) \
+ ? segment->p_paddr != section->lma \
+ : segment->p_vaddr != section->vma) \
|| (strcmp (bfd_get_section_name (ibfd, section), ".dynamic") \
- == 0)) \
- && ! section->segment_mark)
+ == 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) \
LMA. */
#define SEGMENT_OVERLAPS(seg1, seg2) \
( !(SEGMENT_AFTER_SEGMENT (seg1, seg2, p_vaddr) \
- || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_vaddr)) \
+ || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_vaddr)) \
&& !(SEGMENT_AFTER_SEGMENT (seg1, seg2, p_paddr) \
- || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_paddr)))
+ || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_paddr)))
/* Initialise the segment mark field. */
for (section = ibfd->sections; section != NULL; section = section->next)
}
if (segment->p_type != PT_LOAD)
- continue;
+ {
+ /* Remove PT_GNU_RELRO segment. */
+ if (segment->p_type == PT_GNU_RELRO)
+ segment->p_type = PT_NULL;
+ continue;
+ }
/* Determine if this segment overlaps any previous segments. */
- for (j = 0, segment2 = elf_tdata (ibfd)->phdr; j < i; j++, segment2 ++)
+ for (j = 0, segment2 = elf_tdata (ibfd)->phdr; j < i; j++, segment2++)
{
bfd_signed_vma extra_length;
if (segment2->p_type != PT_LOAD
- || ! SEGMENT_OVERLAPS (segment, segment2))
+ || !SEGMENT_OVERLAPS (segment, segment2))
continue;
/* Merge the two segments together. */
if (segment2->p_vaddr < segment->p_vaddr)
{
/* Extend SEGMENT2 to include SEGMENT and then delete
- SEGMENT. */
- extra_length =
- SEGMENT_END (segment, segment->p_vaddr)
- - SEGMENT_END (segment2, segment2->p_vaddr);
+ SEGMENT. */
+ extra_length = (SEGMENT_END (segment, segment->p_vaddr)
+ - SEGMENT_END (segment2, segment2->p_vaddr));
if (extra_length > 0)
{
- segment2->p_memsz += extra_length;
+ segment2->p_memsz += extra_length;
segment2->p_filesz += extra_length;
}
else
{
/* Extend SEGMENT to include SEGMENT2 and then delete
- SEGMENT2. */
- extra_length =
- SEGMENT_END (segment2, segment2->p_vaddr)
- - SEGMENT_END (segment, segment->p_vaddr);
+ SEGMENT2. */
+ extra_length = (SEGMENT_END (segment2, segment2->p_vaddr)
+ - SEGMENT_END (segment, segment->p_vaddr));
if (extra_length > 0)
{
- segment->p_memsz += extra_length;
+ segment->p_memsz += extra_length;
segment->p_filesz += extra_length;
}
/* The second scan attempts to assign sections to segments. */
for (i = 0, segment = elf_tdata (ibfd)->phdr;
i < num_segments;
- i ++, segment ++)
- {
- unsigned int section_count;
- asection ** sections;
- asection * output_section;
- unsigned int isec;
- bfd_vma matching_lma;
- bfd_vma suggested_lma;
- unsigned int j;
+ i++, segment++)
+ {
+ unsigned int section_count;
+ asection **sections;
+ asection *output_section;
+ unsigned int isec;
+ bfd_vma matching_lma;
+ bfd_vma suggested_lma;
+ unsigned int j;
bfd_size_type amt;
+ asection *first_section;
+ bfd_boolean first_matching_lma;
+ bfd_boolean first_suggested_lma;
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;
/* Initialise the fields of the segment map. Default to
using the physical address of the segment in the input BFD. */
- map->next = NULL;
- map->p_type = segment->p_type;
- map->p_flags = segment->p_flags;
+ map->next = NULL;
+ 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->includes_filehdr = (segment->p_offset == 0
&& segment->p_filesz >= iehdr->e_ehsize);
-
map->includes_phdrs = 0;
- if (! phdr_included || segment->p_type != PT_LOAD)
+ if (!phdr_included || segment->p_type != PT_LOAD)
{
map->includes_phdrs =
(segment->p_offset <= (bfd_vma) iehdr->e_phoff
something. They are allowed by the ELF spec however, so only
a warning is produced. */
if (segment->p_type == PT_LOAD)
- (*_bfd_error_handler)
- (_("%B: warning: Empty loadable segment detected, is this intentional ?\n"),
- ibfd);
+ (*_bfd_error_handler) (_("%B: warning: Empty loadable segment"
+ " detected, is this intentional ?\n"),
+ ibfd);
map->count = 0;
*pointer_to_map = map;
isec = 0;
matching_lma = 0;
suggested_lma = 0;
+ first_matching_lma = TRUE;
+ first_suggested_lma = TRUE;
- for (j = 0, section = ibfd->sections;
+ for (section = ibfd->sections;
section != NULL;
section = section->next)
+ if (section == first_section)
+ break;
+
+ for (j = 0; section != NULL; section = section->next)
{
if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed))
{
output_section = section->output_section;
- sections[j ++] = section;
+ sections[j++] = section;
/* The Solaris native linker always sets p_paddr to 0.
We try to catch that case here, and set it to the
p_paddr be left as zero. */
if (segment->p_paddr == 0
&& segment->p_vaddr != 0
- && (! bed->want_p_paddr_set_to_zero)
+ && !bed->want_p_paddr_set_to_zero
&& isec == 0
&& output_section->lma != 0
- && (output_section->vma == (segment->p_vaddr
- + (map->includes_filehdr
- ? iehdr->e_ehsize
- : 0)
- + (map->includes_phdrs
- ? (iehdr->e_phnum
- * iehdr->e_phentsize)
- : 0))))
+ && output_section->vma == (segment->p_vaddr
+ + (map->includes_filehdr
+ ? iehdr->e_ehsize
+ : 0)
+ + (map->includes_phdrs
+ ? (iehdr->e_phnum
+ * iehdr->e_phentsize)
+ : 0)))
map->p_paddr = segment->p_vaddr;
/* Match up the physical address of the segment with the
LMA address of the output section. */
if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr)
|| IS_COREFILE_NOTE (segment, section)
- || (bed->want_p_paddr_set_to_zero &&
- IS_CONTAINED_BY_VMA (output_section, segment))
- )
+ || (bed->want_p_paddr_set_to_zero
+ && IS_CONTAINED_BY_VMA (output_section, segment)))
{
- if (matching_lma == 0)
- matching_lma = output_section->lma;
+ if (first_matching_lma || output_section->lma < matching_lma)
+ {
+ matching_lma = output_section->lma;
+ first_matching_lma = FALSE;
+ }
/* We assume that if the section fits within the segment
then it does not overlap any other section within that
segment. */
- map->sections[isec ++] = output_section;
+ map->sections[isec++] = output_section;
}
- else if (suggested_lma == 0)
- suggested_lma = output_section->lma;
+ else if (first_suggested_lma)
+ {
+ suggested_lma = output_section->lma;
+ first_suggested_lma = FALSE;
+ }
+
+ if (j == section_count)
+ break;
}
}
*pointer_to_map = map;
pointer_to_map = &map->next;
+ if (!bed->want_p_paddr_set_to_zero
+ && 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;
}
else
{
- if (matching_lma != 0)
+ if (!first_matching_lma)
{
/* At least one section fits inside the current segment.
Keep it, but modify its physical address to match the
{
map->count = 0;
suggested_lma = 0;
+ first_suggested_lma = TRUE;
/* Fill the current segment with sections that fit. */
for (j = 0; j < section_count; j++)
/* If the first section in a segment does not start at
the beginning of the segment, then something is
wrong. */
- if (output_section->lma !=
- (map->p_paddr
- + (map->includes_filehdr ? iehdr->e_ehsize : 0)
- + (map->includes_phdrs
- ? iehdr->e_phnum * iehdr->e_phentsize
- : 0)))
+ if (output_section->lma
+ != (map->p_paddr
+ + (map->includes_filehdr ? iehdr->e_ehsize : 0)
+ + (map->includes_phdrs
+ ? iehdr->e_phnum * iehdr->e_phentsize
+ : 0)))
abort ();
}
else
{
- asection * prev_sec;
+ asection *prev_sec;
prev_sec = map->sections[map->count - 1];
if ((BFD_ALIGN (prev_sec->lma + prev_sec->size,
maxpagesize)
< BFD_ALIGN (output_section->lma, maxpagesize))
- || ((prev_sec->lma + prev_sec->size)
+ || (prev_sec->lma + prev_sec->size
> output_section->lma))
{
- if (suggested_lma == 0)
- suggested_lma = output_section->lma;
+ if (first_suggested_lma)
+ {
+ suggested_lma = output_section->lma;
+ first_suggested_lma = FALSE;
+ }
continue;
}
sections[j] = NULL;
section->segment_mark = TRUE;
}
- else if (suggested_lma == 0)
- suggested_lma = output_section->lma;
+ else if (first_suggested_lma)
+ {
+ suggested_lma = output_section->lma;
+ first_suggested_lma = FALSE;
+ }
}
BFD_ASSERT (map->count > 0);
/* Initialise the fields of the segment map. Set the physical
physical address to the LMA of the first section that has
not yet been assigned. */
- map->next = NULL;
- map->p_type = segment->p_type;
- map->p_flags = segment->p_flags;
- map->p_flags_valid = 1;
- map->p_paddr = suggested_lma;
- map->p_paddr_valid = 1;
+ map->next = NULL;
+ map->p_type = segment->p_type;
+ map->p_flags = segment->p_flags;
+ map->p_flags_valid = 1;
+ map->p_paddr = suggested_lma;
+ map->p_paddr_valid = 1;
map->includes_filehdr = 0;
- map->includes_phdrs = 0;
+ map->includes_phdrs = 0;
}
}
while (isec < section_count);
#undef SECTION_SIZE
#undef IS_CONTAINED_BY_VMA
#undef IS_CONTAINED_BY_LMA
+#undef IS_NOTE
#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;
-
- /* FIXME: Do we need to copy PT_NULL segment? */
- if (segment->p_type == PT_NULL)
- continue;
+ asection *first_section = NULL;
+ asection *lowest_section = NULL;
/* Compute how many sections are in this segment. */
for (section = ibfd->sections, section_count = 0;
{
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 = lowest_section = section;
+ if (section->lma < lowest_section->lma)
+ lowest_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;
+
+ if (map->p_type == PT_GNU_RELRO
+ && segment->p_filesz == segment->p_memsz)
+ {
+ /* The PT_GNU_RELRO segment may contain the first a few
+ bytes in the .got.plt section even if the whole .got.plt
+ section isn't in the PT_GNU_RELRO segment. We won't
+ change the size of the PT_GNU_RELRO segment. */
+ map->p_size = segment->p_filesz;
+ map->p_size_valid = 1;
+ }
/* 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 = ((lowest_section ? lowest_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;
Elf_Internal_Shdr *this_hdr;
+ const struct elf_backend_data *bed;
+
+ bed = get_elf_backend_data (ibfd);
+
+ /* Regenerate the segment map if p_paddr is set to 0. */
+ if (bed->want_p_paddr_set_to_zero)
+ goto rewrite;
/* Initialize the segment mark field. */
for (section = obfd->sections; section != NULL;
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)
return TRUE;
/* Don't copy the output ELF section type from input if the
- output BFD section flags has been set to something different.
+ 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.
See elfNN_ia64_object_p in elfxx-ia64.c. */
-
if (need_group)
{
if (elf_sec_group (isec) == NULL
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;
}
osym = elf_symbol_from (obfd, osymarg);
if (isym != NULL
+ && isym->internal_elf_sym.st_shndx != 0
&& osym != NULL
&& bfd_is_abs_section (isym->symbol.section))
{
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;
sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
}
else if (bfd_is_com_section (syms[idx]->section))
- sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
+ sym.st_info = ELF_ST_INFO (STB_GLOBAL,
+#ifdef USE_STT_COMMON
+ type == STT_OBJECT ? STT_COMMON :
+#endif
+ type);
else if (bfd_is_und_section (syms[idx]->section))
sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK)
? STB_WEAK
}
int
-_bfd_elf_sizeof_headers (bfd *abfd, bfd_boolean reloc)
+_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;
+
+ if (!info->relocatable)
+ {
+ 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;
+ }
- ret = get_elf_backend_data (abfd)->s->sizeof_ehdr;
- if (! reloc)
- ret += get_program_header_size (abfd);
return ret;
}
if (bfd_get_section_by_name (abfd, name) != NULL)
return TRUE;
- sect2 = bfd_make_section (abfd, name);
+ sect2 = bfd_make_section_with_flags (abfd, name, sect->flags);
if (sect2 == NULL)
return FALSE;
sect2->size = sect->size;
sect2->filepos = sect->filepos;
- sect2->flags = sect->flags;
sect2->alignment_power = sect->alignment_power;
return TRUE;
}
return FALSE;
memcpy (threaded_name, buf, len);
- sect = bfd_make_section_anyway (abfd, threaded_name);
+ sect = bfd_make_section_anyway_with_flags (abfd, threaded_name,
+ SEC_HAS_CONTENTS);
if (sect == NULL)
return FALSE;
sect->size = size;
sect->filepos = filepos;
- sect->flags = SEC_HAS_CONTENTS;
sect->alignment_power = 2;
return elfcore_maybe_make_sect (abfd, name, sect);
}
/* Linux dumps the Intel SSE regs in a note named "LINUX" with a note
- type of 5 (NT_PRXFPREG). Just include the whole note's contents
+ type of NT_PRXFPREG. Just include the whole note's contents
literally. */
static bfd_boolean
return elfcore_make_note_pseudosection (abfd, ".reg-xfp", note);
}
+static bfd_boolean
+elfcore_grok_ppc_vmx (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-vmx", note);
+}
+
+
#if defined (HAVE_PRPSINFO_T)
typedef prpsinfo_t elfcore_psinfo_t;
#if defined (HAVE_PRPSINFO32_T) /* Sparc64 cross Sparc32 */
return FALSE;
memcpy (name, buf, len);
- sect = bfd_make_section_anyway (abfd, name);
+ sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
if (sect == NULL)
return FALSE;
sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_reg);
#endif
- sect->flags = SEC_HAS_CONTENTS;
sect->alignment_power = 2;
if (!elfcore_maybe_make_sect (abfd, ".reg", sect))
return FALSE;
memcpy (name, buf, len);
- sect = bfd_make_section_anyway (abfd, name);
+ sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
if (sect == NULL)
return FALSE;
sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_fpreg);
#endif
- sect->flags = SEC_HAS_CONTENTS;
sect->alignment_power = 2;
return elfcore_maybe_make_sect (abfd, ".reg2", sect);
}
#endif /* defined (HAVE_LWPSTATUS_T) */
-#if defined (HAVE_WIN32_PSTATUS_T)
static bfd_boolean
elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note)
{
char *name;
size_t len;
asection *sect;
- win32_pstatus_t pstatus;
+ int type;
+ int is_active_thread;
+ bfd_vma base_addr;
- if (note->descsz < sizeof (pstatus))
+ if (note->descsz < 728)
return TRUE;
- memcpy (&pstatus, note->descdata, sizeof (pstatus));
+ if (! CONST_STRNEQ (note->namedata, "win32"))
+ return TRUE;
+
+ type = bfd_get_32 (abfd, note->descdata);
- switch (pstatus.data_type)
+ switch (type)
{
- case NOTE_INFO_PROCESS:
+ case 1 /* NOTE_INFO_PROCESS */:
/* FIXME: need to add ->core_command. */
- elf_tdata (abfd)->core_signal = pstatus.data.process_info.signal;
- elf_tdata (abfd)->core_pid = pstatus.data.process_info.pid;
+ /* process_info.pid */
+ elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 8);
+ /* process_info.signal */
+ elf_tdata (abfd)->core_signal = bfd_get_32 (abfd, note->descdata + 12);
break;
- case NOTE_INFO_THREAD:
+ case 2 /* NOTE_INFO_THREAD */:
/* Make a ".reg/999" section. */
- sprintf (buf, ".reg/%ld", (long) pstatus.data.thread_info.tid);
+ /* thread_info.tid */
+ sprintf (buf, ".reg/%ld", (long) bfd_get_32 (abfd, note->descdata + 8));
len = strlen (buf) + 1;
name = bfd_alloc (abfd, len);
memcpy (name, buf, len);
- sect = bfd_make_section_anyway (abfd, name);
+ sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
if (sect == NULL)
return FALSE;
- sect->size = sizeof (pstatus.data.thread_info.thread_context);
- sect->filepos = (note->descpos
- + offsetof (struct win32_pstatus,
- data.thread_info.thread_context));
- sect->flags = SEC_HAS_CONTENTS;
+ /* sizeof (thread_info.thread_context) */
+ sect->size = 716;
+ /* offsetof (thread_info.thread_context) */
+ sect->filepos = note->descpos + 12;
sect->alignment_power = 2;
- if (pstatus.data.thread_info.is_active_thread)
+ /* thread_info.is_active_thread */
+ is_active_thread = bfd_get_32 (abfd, note->descdata + 8);
+
+ if (is_active_thread)
if (! elfcore_maybe_make_sect (abfd, ".reg", sect))
return FALSE;
break;
- case NOTE_INFO_MODULE:
+ case 3 /* NOTE_INFO_MODULE */:
/* Make a ".module/xxxxxxxx" section. */
- sprintf (buf, ".module/%08lx",
- (long) pstatus.data.module_info.base_address);
+ /* module_info.base_address */
+ base_addr = bfd_get_32 (abfd, note->descdata + 4);
+ sprintf (buf, ".module/%08lx", (long) base_addr);
len = strlen (buf) + 1;
name = bfd_alloc (abfd, len);
memcpy (name, buf, len);
- sect = bfd_make_section_anyway (abfd, name);
+ sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
if (sect == NULL)
return FALSE;
sect->size = note->descsz;
sect->filepos = note->descpos;
- sect->flags = SEC_HAS_CONTENTS;
sect->alignment_power = 2;
break;
return TRUE;
}
-#endif /* HAVE_WIN32_PSTATUS_T */
static bfd_boolean
elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note)
case NT_FPREGSET: /* FIXME: rename to NT_PRFPREG */
return elfcore_grok_prfpreg (abfd, note);
-#if defined (HAVE_WIN32_PSTATUS_T)
case NT_WIN32PSTATUS:
return elfcore_grok_win32pstatus (abfd, note);
-#endif
case NT_PRXFPREG: /* Linux SSE extension */
if (note->namesz == 6
else
return TRUE;
+ case NT_PPC_VMX:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_vmx (abfd, note);
+ else
+ return TRUE;
+
case NT_PRPSINFO:
case NT_PSINFO:
if (bed->elf_backend_grok_psinfo)
case NT_AUXV:
{
- asection *sect = bfd_make_section_anyway (abfd, ".auxv");
+ asection *sect = bfd_make_section_anyway_with_flags (abfd, ".auxv",
+ SEC_HAS_CONTENTS);
if (sect == NULL)
return FALSE;
sect->size = note->descsz;
sect->filepos = note->descpos;
- sect->flags = SEC_HAS_CONTENTS;
sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32;
- return TRUE;
- }
+ return TRUE;
+ }
+ }
+}
+
+static bfd_boolean
+elfobj_grok_gnu_build_id (bfd *abfd, Elf_Internal_Note *note)
+{
+ elf_tdata (abfd)->build_id_size = note->descsz;
+ elf_tdata (abfd)->build_id = bfd_alloc (abfd, note->descsz);
+ if (elf_tdata (abfd)->build_id == NULL)
+ return FALSE;
+
+ memcpy (elf_tdata (abfd)->build_id, note->descdata, note->descsz);
+
+ return TRUE;
+}
+
+static bfd_boolean
+elfobj_grok_gnu_note (bfd *abfd, Elf_Internal_Note *note)
+{
+ switch (note->type)
+ {
+ default:
+ return TRUE;
+
+ case NT_GNU_BUILD_ID:
+ return elfobj_grok_gnu_build_id (abfd, note);
}
}
static bfd_boolean
elfcore_grok_netbsd_procinfo (bfd *abfd, Elf_Internal_Note *note)
{
-
/* Signal number at offset 0x08. */
elf_tdata (abfd)->core_signal
= bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x08);
if (note->type == NT_NETBSDCORE_PROCINFO)
{
/* NetBSD-specific core "procinfo". Note that we expect to
- find this note before any of the others, which is fine,
- since the kernel writes this note out first when it
- creates a core file. */
+ find this note before any of the others, which is fine,
+ since the kernel writes this note out first when it
+ creates a core file. */
return elfcore_grok_netbsd_procinfo (abfd, note);
}
switch (bfd_get_arch (abfd))
{
- /* On the Alpha, SPARC (32-bit and 64-bit), PT_GETREGS == mach+0 and
- PT_GETFPREGS == mach+2. */
+ /* On the Alpha, SPARC (32-bit and 64-bit), PT_GETREGS == mach+0 and
+ PT_GETFPREGS == mach+2. */
case bfd_arch_alpha:
case bfd_arch_sparc:
switch (note->type)
- {
- case NT_NETBSDCORE_FIRSTMACH+0:
- return elfcore_make_note_pseudosection (abfd, ".reg", note);
+ {
+ case NT_NETBSDCORE_FIRSTMACH+0:
+ return elfcore_make_note_pseudosection (abfd, ".reg", note);
- case NT_NETBSDCORE_FIRSTMACH+2:
- return elfcore_make_note_pseudosection (abfd, ".reg2", note);
+ case NT_NETBSDCORE_FIRSTMACH+2:
+ return elfcore_make_note_pseudosection (abfd, ".reg2", note);
- default:
- return TRUE;
- }
+ default:
+ return TRUE;
+ }
- /* On all other arch's, PT_GETREGS == mach+1 and
- PT_GETFPREGS == mach+3. */
+ /* On all other arch's, PT_GETREGS == mach+1 and
+ PT_GETFPREGS == mach+3. */
default:
switch (note->type)
- {
- case NT_NETBSDCORE_FIRSTMACH+1:
- return elfcore_make_note_pseudosection (abfd, ".reg", note);
+ {
+ case NT_NETBSDCORE_FIRSTMACH+1:
+ return elfcore_make_note_pseudosection (abfd, ".reg", note);
- case NT_NETBSDCORE_FIRSTMACH+3:
- return elfcore_make_note_pseudosection (abfd, ".reg2", note);
+ case NT_NETBSDCORE_FIRSTMACH+3:
+ return elfcore_make_note_pseudosection (abfd, ".reg2", note);
- default:
- return TRUE;
- }
+ default:
+ return TRUE;
+ }
}
/* NOTREACHED */
}
static bfd_boolean
-elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, pid_t *tid)
+elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, long *tid)
{
void *ddata = note->descdata;
char buf[100];
elf_tdata (abfd)->core_lwpid = *tid;
/* Make a ".qnx_core_status/%d" section. */
- sprintf (buf, ".qnx_core_status/%ld", (long) *tid);
+ sprintf (buf, ".qnx_core_status/%ld", *tid);
name = bfd_alloc (abfd, strlen (buf) + 1);
if (name == NULL)
return FALSE;
strcpy (name, buf);
- sect = bfd_make_section_anyway (abfd, name);
+ sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
if (sect == NULL)
return FALSE;
sect->size = note->descsz;
sect->filepos = note->descpos;
- sect->flags = SEC_HAS_CONTENTS;
sect->alignment_power = 2;
return (elfcore_maybe_make_sect (abfd, ".qnx_core_status", sect));
static bfd_boolean
elfcore_grok_nto_regs (bfd *abfd,
Elf_Internal_Note *note,
- pid_t tid,
+ long tid,
char *base)
{
char buf[100];
asection *sect;
/* Make a "(base)/%d" section. */
- sprintf (buf, "%s/%ld", base, (long) tid);
+ sprintf (buf, "%s/%ld", base, tid);
name = bfd_alloc (abfd, strlen (buf) + 1);
if (name == NULL)
return FALSE;
strcpy (name, buf);
- sect = bfd_make_section_anyway (abfd, name);
+ sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
if (sect == NULL)
return FALSE;
sect->size = note->descsz;
sect->filepos = note->descpos;
- sect->flags = SEC_HAS_CONTENTS;
sect->alignment_power = 2;
/* This is the current thread. */
/* Every GREG section has a STATUS section before it. Store the
tid from the previous call to pass down to the next gregs
function. */
- static pid_t tid = 1;
+ static long tid = 1;
switch (note->type)
{
}
}
+static bfd_boolean
+elfcore_grok_spu_note (bfd *abfd, Elf_Internal_Note *note)
+{
+ char *name;
+ asection *sect;
+ size_t len;
+
+ /* Use note name as section name. */
+ len = note->namesz;
+ name = bfd_alloc (abfd, len);
+ if (name == NULL)
+ return FALSE;
+ memcpy (name, note->namedata, len);
+ name[len - 1] = '\0';
+
+ sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS);
+ if (sect == NULL)
+ return FALSE;
+
+ sect->size = note->descsz;
+ sect->filepos = note->descpos;
+ sect->alignment_power = 1;
+
+ return TRUE;
+}
+
/* 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);
+ if (buf == NULL)
+ return buf;
+ 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);
}
note_name, NT_PRXFPREG, xfpregs, size);
}
+char *
+elfcore_write_ppc_vmx (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_vmx,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_VMX, ppc_vmx, size);
+}
+
static bfd_boolean
-elfcore_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size)
+elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset)
{
- char *buf;
char *p;
- if (size <= 0)
- return TRUE;
-
- if (bfd_seek (abfd, offset, SEEK_SET) != 0)
- return FALSE;
-
- buf = bfd_malloc (size);
- if (buf == NULL)
- return FALSE;
-
- if (bfd_bread (buf, size, abfd) != size)
- {
- error:
- free (buf);
- return FALSE;
- }
-
p = buf;
while (p < buf + size)
{
in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4);
in.descpos = offset + (in.descdata - buf);
- if (strncmp (in.namedata, "NetBSD-CORE", 11) == 0)
+ switch (bfd_get_format (abfd))
{
- if (! elfcore_grok_netbsd_note (abfd, &in))
- goto error;
- }
- else if (strncmp (in.namedata, "QNX", 3) == 0)
- {
- if (! elfcore_grok_nto_note (abfd, &in))
- goto error;
+ default:
+ return TRUE;
+
+ case bfd_core:
+ if (CONST_STRNEQ (in.namedata, "NetBSD-CORE"))
+ {
+ if (! elfcore_grok_netbsd_note (abfd, &in))
+ return FALSE;
+ }
+ else if (CONST_STRNEQ (in.namedata, "QNX"))
+ {
+ if (! elfcore_grok_nto_note (abfd, &in))
+ return FALSE;
+ }
+ else if (CONST_STRNEQ (in.namedata, "SPU/"))
+ {
+ if (! elfcore_grok_spu_note (abfd, &in))
+ return FALSE;
+ }
+ else
+ {
+ if (! elfcore_grok_note (abfd, &in))
+ return FALSE;
+ }
+ break;
+
+ case bfd_object:
+ if (in.namesz == sizeof "GNU" && strcmp (in.namedata, "GNU") == 0)
+ {
+ if (! elfobj_grok_gnu_note (abfd, &in))
+ return FALSE;
+ }
+ break;
}
- else
- {
- if (! elfcore_grok_note (abfd, &in))
- goto error;
- }
p = in.descdata + BFD_ALIGN (in.descsz, 4);
}
+ return TRUE;
+}
+
+static bfd_boolean
+elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size)
+{
+ char *buf;
+
+ if (size <= 0)
+ return TRUE;
+
+ if (bfd_seek (abfd, offset, SEEK_SET) != 0)
+ return FALSE;
+
+ buf = bfd_malloc (size);
+ if (buf == NULL)
+ return FALSE;
+
+ if (bfd_bread (buf, size, abfd) != size
+ || !elf_parse_notes (abfd, buf, size, offset))
+ {
+ free (buf);
+ return FALSE;
+ }
+
free (buf);
return TRUE;
}
return num_phdrs;
}
-void
-_bfd_elf_sprintf_vma (bfd *abfd ATTRIBUTE_UNUSED, char *buf, bfd_vma value)
-{
-#ifdef BFD64
- Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */
-
- i_ehdrp = elf_elfheader (abfd);
- if (i_ehdrp == NULL)
- sprintf_vma (buf, value);
- else
- {
- if (i_ehdrp->e_ident[EI_CLASS] == ELFCLASS64)
- {
-#if BFD_HOST_64BIT_LONG
- sprintf (buf, "%016lx", value);
-#else
- sprintf (buf, "%08lx%08lx", _bfd_int64_high (value),
- _bfd_int64_low (value));
-#endif
- }
- else
- sprintf (buf, "%08lx", (unsigned long) (value & 0xffffffff));
- }
-#else
- sprintf_vma (buf, value);
-#endif
-}
-
-void
-_bfd_elf_fprintf_vma (bfd *abfd ATTRIBUTE_UNUSED, void *stream, bfd_vma value)
-{
-#ifdef BFD64
- Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */
-
- i_ehdrp = elf_elfheader (abfd);
- if (i_ehdrp == NULL)
- fprintf_vma ((FILE *) stream, value);
- else
- {
- if (i_ehdrp->e_ident[EI_CLASS] == ELFCLASS64)
- {
-#if BFD_HOST_64BIT_LONG
- fprintf ((FILE *) stream, "%016lx", value);
-#else
- fprintf ((FILE *) stream, "%08lx%08lx",
- _bfd_int64_high (value), _bfd_int64_low (value));
-#endif
- }
- else
- fprintf ((FILE *) stream, "%08lx",
- (unsigned long) (value & 0xffffffff));
- }
-#else
- fprintf_vma ((FILE *) stream, value);
-#endif
-}
-
enum elf_reloc_type_class
_bfd_elf_reloc_type_class (const Elf_Internal_Rela *rela ATTRIBUTE_UNUSED)
{
count = relplt->size / hdr->sh_entsize;
size = count * sizeof (asymbol);
p = relplt->relocation;
- for (i = 0; i < count; i++, s++, p++)
+ for (i = 0; i < count; i++, p++)
size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
s = *ret = bfd_malloc (size);
names = (char *) (s + count);
p = relplt->relocation;
n = 0;
- for (i = 0; i < count; i++, s++, p++)
+ for (i = 0; i < count; i++, p++)
{
size_t len;
bfd_vma addr;
s->section = plt;
s->value = addr - plt->vma;
s->name = names;
+ s->udata.p = NULL;
len = strlen ((*p->sym_ptr_ptr)->name);
memcpy (names, (*p->sym_ptr_ptr)->name, len);
names += len;
memcpy (names, "@plt", sizeof ("@plt"));
names += sizeof ("@plt");
- ++n;
+ ++s, ++n;
}
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)
-{
- 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;
-
- /* Sorted by binding. */
- return ELF_ST_BIND (s1->st_info) - ELF_ST_BIND (s2->st_info);
-}
-
-struct elf_symbol
-{
- Elf_Internal_Sym *sym;
- const char *name;
-};
+/* It is only used by x86-64 so far. */
+asection _bfd_elf_large_com_section
+ = BFD_FAKE_SECTION (_bfd_elf_large_com_section,
+ SEC_IS_COMMON, NULL, "LARGE_COMMON", 0);
-static int
-elf_sym_name_compare (const void *arg1, const void *arg2)
+void
+_bfd_elf_set_osabi (bfd * abfd,
+ struct bfd_link_info * link_info ATTRIBUTE_UNUSED)
{
- const struct elf_symbol *s1 = (const struct elf_symbol *) arg1;
- const struct elf_symbol *s2 = (const struct elf_symbol *) arg2;
- return strcmp (s1->name, s2->name);
-}
-
-/* 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 *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;
- bfd_size_type count1, count2, i;
- int shndx1, shndx2;
- bfd_boolean result;
-
- bfd1 = sec1->owner;
- bfd2 = sec2->owner;
-
- /* 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)
- return strcmp (sec1->name + sizeof ".gnu.linkonce",
- sec2->name + sizeof ".gnu.linkonce") == 0;
-
- /* Both sections have to be in ELF. */
- if (bfd_get_flavour (bfd1) != bfd_target_elf_flavour
- || bfd_get_flavour (bfd2) != bfd_target_elf_flavour)
- return FALSE;
-
- if (elf_section_type (sec1) != elf_section_type (sec2))
- return FALSE;
-
- if ((elf_section_flags (sec1) & SHF_GROUP) != 0
- && (elf_section_flags (sec2) & SHF_GROUP) != 0)
- {
- /* If both are members of section groups, they have to have the
- same group name. */
- if (strcmp (elf_group_name (sec1), elf_group_name (sec2)) != 0)
- return FALSE;
- }
-
- shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1);
- shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2);
- if (shndx1 == -1 || shndx2 == -1)
- return FALSE;
-
- bed1 = get_elf_backend_data (bfd1);
- bed2 = get_elf_backend_data (bfd2);
- hdr1 = &elf_tdata (bfd1)->symtab_hdr;
- symcount1 = hdr1->sh_size / bed1->s->sizeof_sym;
- hdr2 = &elf_tdata (bfd2)->symtab_hdr;
- symcount2 = hdr2->sh_size / bed2->s->sizeof_sym;
-
- 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;
-
- /* 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);
-
- /* Count definitions in the section. */
- count1 = 0;
- for (isym = isymbuf1, isymend = isym + symcount1;
- isym < isymend; isym++)
- {
- if (isym->st_shndx == (unsigned int) shndx1)
- {
- if (count1 == 0)
- isymstart1 = isym;
- count1++;
- }
-
- if (count1 && isym->st_shndx != (unsigned int) shndx1)
- break;
- }
-
- count2 = 0;
- for (isym = isymbuf2, isymend = isym + symcount2;
- isym < isymend; isym++)
- {
- if (isym->st_shndx == (unsigned int) shndx2)
- {
- if (count2 == 0)
- isymstart2 = isym;
- count2++;
- }
-
- if (count2 && isym->st_shndx != (unsigned int) shndx2)
- break;
- }
+ Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form. */
- if (count1 == 0 || count2 == 0 || count1 != count2)
- goto done;
-
- symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol));
- symtable2 = bfd_malloc (count1 * sizeof (struct elf_symbol));
-
- if (symtable1 == NULL || symtable2 == NULL)
- 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++;
- }
-
- /* 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].sym->st_info != symtable2 [i].sym->st_info
- || symtable1 [i].sym->st_other != symtable2 [i].sym->st_other
- || strcmp (symtable1 [i].name, symtable2 [i].name) != 0)
- goto done;
-
- result = TRUE;
-
-done:
- if (symtable1)
- free (symtable1);
- if (symtable2)
- free (symtable2);
- if (isymbuf1)
- free (isymbuf1);
- if (isymbuf2)
- free (isymbuf2);
+ i_ehdrp = elf_elfheader (abfd);
- return result;
+ i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
}
-/* It is only used by x86-64 so far. */
-asection _bfd_elf_large_com_section
- = BFD_FAKE_SECTION (_bfd_elf_large_com_section,
- SEC_IS_COMMON, NULL, "LARGE_COMMON", 0);
-/* Return TRUE if 2 section types are compatible. */
+/* 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_match_sections_by_type (bfd *abfd, const asection *asec,
- bfd *bbfd, const asection *bsec)
+_bfd_elf_is_function_type (unsigned int type)
{
- if (asec == NULL
- || bsec == NULL
- || abfd->xvec->flavour != bfd_target_elf_flavour
- || bbfd->xvec->flavour != bfd_target_elf_flavour)
- return TRUE;
-
- return elf_section_type (asec) == elf_section_type (bsec);
+ return (type == STT_FUNC);
}