/* ELF executable support for BFD.
- Copyright (C) 1993-2015 Free Software Foundation, Inc.
+ Copyright (C) 1993-2017 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
#include "elf-bfd.h"
#include "libiberty.h"
#include "safe-ctype.h"
-#include "elf-linux-psinfo.h"
+#include "elf-linux-core.h"
#ifdef CORE_HEADER
#include CORE_HEADER
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 swap_out_syms (bfd *, struct elf_strtab_hash **, int) ;
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);
if (hdr->sh_type != SHT_STRTAB && hdr->sh_type < SHT_LOOS)
{
/* PR 17512: file: f057ec89. */
+ /* xgettext:c-format */
_bfd_error_handler (_("%B: attempt to load strings from a non-string section (number %d)"),
abfd, shindex);
return NULL;
}
-
+
if (bfd_elf_get_str_section (abfd, shindex) == NULL)
return NULL;
}
if (strindex >= hdr->sh_size)
{
unsigned int shstrndx = elf_elfheader(abfd)->e_shstrndx;
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: invalid string offset %u >= %lu for section `%s'"),
abfd, strindex, (unsigned long) hdr->sh_size,
(shindex == shstrndx && strindex == hdr->sh_name
/* Normal syms might have section extension entries. */
shndx_hdr = NULL;
- if (symtab_hdr == &elf_tdata (ibfd)->symtab_hdr)
- shndx_hdr = &elf_tdata (ibfd)->symtab_shndx_hdr;
+ if (elf_symtab_shndx_list (ibfd) != NULL)
+ {
+ elf_section_list * entry;
+ Elf_Internal_Shdr **sections = elf_elfsections (ibfd);
+
+ /* Find an index section that is linked to this symtab section. */
+ for (entry = elf_symtab_shndx_list (ibfd); entry != NULL; entry = entry->next)
+ {
+ /* PR 20063. */
+ if (entry->hdr.sh_link >= elf_numsections (ibfd))
+ continue;
+
+ if (sections[entry->hdr.sh_link] == symtab_hdr)
+ {
+ shndx_hdr = & entry->hdr;
+ break;
+ };
+ }
+
+ if (shndx_hdr == NULL)
+ {
+ if (symtab_hdr == & elf_symtab_hdr (ibfd))
+ /* Not really accurate, but this was how the old code used to work. */
+ shndx_hdr = & elf_symtab_shndx_list (ibfd)->hdr;
+ /* Otherwise we do nothing. The assumption is that
+ the index table will not be needed. */
+ }
+ }
/* Read the symbols. */
alloc_ext = NULL;
alloc_intsym = NULL;
bed = get_elf_backend_data (ibfd);
extsym_size = bed->s->sizeof_sym;
- amt = symcount * extsym_size;
+ amt = (bfd_size_type) symcount * extsym_size;
pos = symtab_hdr->sh_offset + symoffset * extsym_size;
if (extsym_buf == NULL)
{
extshndx_buf = NULL;
else
{
- amt = symcount * sizeof (Elf_External_Sym_Shndx);
+ amt = (bfd_size_type) symcount * sizeof (Elf_External_Sym_Shndx);
pos = shndx_hdr->sh_offset + symoffset * sizeof (Elf_External_Sym_Shndx);
if (extshndx_buf == NULL)
{
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);
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%B symbol number %lu references "
+ "nonexistent SHT_SYMTAB_SHNDX section"),
+ ibfd, (unsigned long) symoffset);
if (alloc_intsym != NULL)
free (alloc_intsym);
intsym_buf = NULL;
if (shdr->contents == NULL)
{
_bfd_error_handler
+ /* xgettext:c-format */
(_("%B: corrupt size field in group section header: 0x%lx"), abfd, shdr->sh_size);
bfd_set_error (bfd_error_bad_value);
-- num_group;
!= shdr->sh_size))
{
_bfd_error_handler
+ /* xgettext:c-format */
(_("%B: invalid size field in group section header: 0x%lx"), abfd, shdr->sh_size);
bfd_set_error (bfd_error_bad_value);
-- num_group;
}
if (idx >= shnum)
{
- ((*_bfd_error_handler)
- (_("%B: invalid SHT_GROUP entry"), abfd));
+ _bfd_error_handler
+ (_("%B: invalid SHT_GROUP entry"), abfd);
idx = 0;
}
dest->shdr = elf_elfsections (abfd)[idx];
{
elf_tdata (abfd)->group_sect_ptr = NULL;
elf_tdata (abfd)->num_group = num_group = -1;
- (*_bfd_error_handler) (_("%B: no valid group sections found"), abfd);
+ _bfd_error_handler
+ (_("%B: no valid group sections found"), abfd);
bfd_set_error (bfd_error_bad_value);
}
}
if (elf_group_name (newsect) == NULL)
{
- (*_bfd_error_handler) (_("%B: no group info for section %A"),
- abfd, newsect);
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%B: no group info for section %A"),
+ abfd, newsect);
return FALSE;
}
return TRUE;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
if (bed->link_order_error_handler)
bed->link_order_error_handler
+ /* xgettext:c-format */
(_("%B: warning: sh_link not set for section `%A'"),
abfd, s);
}
sh_link. We don't want to proceed. */
if (linksec == NULL)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: sh_link [%d] in section `%A' is incorrect"),
s->owner, s, elfsec);
result = FALSE;
elf_linked_to_section (s) = linksec;
}
}
+ else if (this_hdr->sh_type == SHT_GROUP
+ && elf_next_in_group (s) == NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%B: SHT_GROUP section [index %d] has no SHF_GROUP sections"),
+ abfd, elf_section_data (s)->this_idx);
+ result = FALSE;
+ }
}
/* Process section groups. */
for (i = 0; i < num_group; i++)
{
Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i];
- Elf_Internal_Group *idx = (Elf_Internal_Group *) shdr->contents;
- unsigned int n_elt = shdr->sh_size / 4;
+ Elf_Internal_Group *idx;
+ unsigned int n_elt;
+
+ /* PR binutils/18758: Beware of corrupt binaries with invalid group data. */
+ if (shdr == NULL || shdr->bfd_section == NULL || shdr->contents == NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%B: section group entry number %u is corrupt"),
+ abfd, i);
+ result = FALSE;
+ continue;
+ }
+
+ idx = (Elf_Internal_Group *) shdr->contents;
+ n_elt = shdr->sh_size / 4;
while (--n_elt != 0)
if ((++idx)->shdr->bfd_section)
else
{
/* There are some unknown sections in the group. */
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: unknown [%d] section `%s' in group [%s]"),
abfd,
(unsigned int) idx->shdr->sh_type,
return elf_next_in_group (sec) != NULL;
}
+static char *
+convert_debug_to_zdebug (bfd *abfd, const char *name)
+{
+ unsigned int len = strlen (name);
+ char *new_name = bfd_alloc (abfd, len + 2);
+ if (new_name == NULL)
+ return NULL;
+ new_name[0] = '.';
+ new_name[1] = 'z';
+ memcpy (new_name + 2, name + 1, len);
+ return new_name;
+}
+
+static char *
+convert_zdebug_to_debug (bfd *abfd, const char *name)
+{
+ unsigned int len = strlen (name);
+ char *new_name = bfd_alloc (abfd, len);
+ if (new_name == NULL)
+ return NULL;
+ new_name[0] = '.';
+ memcpy (new_name + 1, name + 2, len - 1);
+ return new_name;
+}
+
/* Make a BFD section from an ELF section. We store a pointer to the
BFD section in the bfd_section field of the header. */
{
flags |= SEC_MERGE;
newsect->entsize = hdr->sh_entsize;
- if ((hdr->sh_flags & SHF_STRINGS) != 0)
- flags |= SEC_STRINGS;
}
+ if ((hdr->sh_flags & SHF_STRINGS) != 0)
+ flags |= SEC_STRINGS;
if (hdr->sh_flags & SHF_GROUP)
if (!setup_group (abfd, hdr, newsect))
return FALSE;
if (!bfd_malloc_and_get_section (abfd, newsect, &contents))
return FALSE;
- elf_parse_notes (abfd, (char *) contents, hdr->sh_size, -1);
+ elf_parse_notes (abfd, (char *) contents, hdr->sh_size, hdr->sh_offset);
free (contents);
}
|| (name[1] == 'z' && name[7] == '_')))
{
enum { nothing, compress, decompress } action = nothing;
- char *new_name;
int compression_header_size;
+ bfd_size_type uncompressed_size;
bfd_boolean compressed
= bfd_is_section_compressed_with_header (abfd, newsect,
- &compression_header_size);
+ &compression_header_size,
+ &uncompressed_size);
if (compressed)
{
if (newsect->size != 0
&& (abfd->flags & BFD_COMPRESS)
&& compression_header_size >= 0
+ && uncompressed_size > 0
&& (!compressed
|| ((compression_header_size > 0)
!= ((abfd->flags & BFD_COMPRESS_GABI) != 0))))
{
if (!bfd_init_section_compress_status (abfd, newsect))
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: unable to initialize compress status for section %s"),
abfd, name);
return FALSE;
{
if (!bfd_init_section_decompress_status (abfd, newsect))
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: unable to initialize decompress status for section %s"),
abfd, name);
return FALSE;
}
}
- new_name = NULL;
- if (action == decompress
- || (action == compress
- && (abfd->flags & BFD_COMPRESS_GABI) != 0))
- {
- if (name[1] == 'z')
- {
- unsigned int len = strlen (name);
-
- new_name = bfd_alloc (abfd, len);
- if (new_name == NULL)
- return FALSE;
- new_name[0] = '.';
- memcpy (new_name + 1, name + 2, len - 1);
- }
- }
- else if (action == compress
- && newsect->compress_status == COMPRESS_SECTION_DONE)
+ if (abfd->is_linker_input)
{
- /* PR binutils/18087: Compression does not always make a section
- smaller. So only rename the section when compression has
- actually taken place. */
- if (name[1] != 'z')
+ if (name[1] == 'z'
+ && (action == decompress
+ || (action == compress
+ && (abfd->flags & BFD_COMPRESS_GABI) != 0)))
{
- unsigned int len = strlen (name);
-
- new_name = bfd_alloc (abfd, len + 2);
+ /* Convert section name from .zdebug_* to .debug_* so
+ that linker will consider this section as a debug
+ section. */
+ char *new_name = convert_zdebug_to_debug (abfd, name);
if (new_name == NULL)
return FALSE;
- new_name[0] = '.';
- new_name[1] = 'z';
- memcpy (new_name + 2, name + 1, len);
+ bfd_rename_section (abfd, newsect, new_name);
}
}
- if (new_name != NULL)
- bfd_rename_section (abfd, newsect, new_name);
+ else
+ /* For objdump, don't rename the section. For objcopy, delay
+ section rename to elf_fake_sections. */
+ newsect->flags |= SEC_ELF_RENAME;
}
return TRUE;
}
-const char *const bfd_elf_section_type_names[] = {
+const char *const bfd_elf_section_type_names[] =
+{
"SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB",
"SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE",
"SHT_NOBITS", "SHT_REL", "SHT_SHLIB", "SHT_DYNSYM",
return bfd_reloc_continue;
}
\f
+/* Returns TRUE if section A matches section B.
+ Names, addresses and links may be different, but everything else
+ should be the same. */
+
+static bfd_boolean
+section_match (const Elf_Internal_Shdr * a,
+ const Elf_Internal_Shdr * b)
+{
+ return
+ a->sh_type == b->sh_type
+ && (a->sh_flags & ~ SHF_INFO_LINK)
+ == (b->sh_flags & ~ SHF_INFO_LINK)
+ && a->sh_addralign == b->sh_addralign
+ && a->sh_size == b->sh_size
+ && a->sh_entsize == b->sh_entsize
+ /* FIXME: Check sh_addr ? */
+ ;
+}
+
+/* Find a section in OBFD that has the same characteristics
+ as IHEADER. Return the index of this section or SHN_UNDEF if
+ none can be found. Check's section HINT first, as this is likely
+ to be the correct section. */
+
+static unsigned int
+find_link (const bfd * obfd, const Elf_Internal_Shdr * iheader, const unsigned int hint)
+{
+ Elf_Internal_Shdr ** oheaders = elf_elfsections (obfd);
+ unsigned int i;
+
+ BFD_ASSERT (iheader != NULL);
+
+ /* See PR 20922 for a reproducer of the NULL test. */
+ if (oheaders[hint] != NULL
+ && section_match (oheaders[hint], iheader))
+ return hint;
+
+ for (i = 1; i < elf_numsections (obfd); i++)
+ {
+ Elf_Internal_Shdr * oheader = oheaders[i];
+
+ if (oheader == NULL)
+ continue;
+ if (section_match (oheader, iheader))
+ /* FIXME: Do we care if there is a potential for
+ multiple matches ? */
+ return i;
+ }
+
+ return SHN_UNDEF;
+}
+
+/* PR 19938: Attempt to set the ELF section header fields of an OS or
+ Processor specific section, based upon a matching input section.
+ Returns TRUE upon success, FALSE otherwise. */
+
+static bfd_boolean
+copy_special_section_fields (const bfd *ibfd,
+ bfd *obfd,
+ const Elf_Internal_Shdr *iheader,
+ Elf_Internal_Shdr *oheader,
+ const unsigned int secnum)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (obfd);
+ const Elf_Internal_Shdr **iheaders = (const Elf_Internal_Shdr **) elf_elfsections (ibfd);
+ bfd_boolean changed = FALSE;
+ unsigned int sh_link;
+
+ if (oheader->sh_type == SHT_NOBITS)
+ {
+ /* This is a feature for objcopy --only-keep-debug:
+ When a section's type is changed to NOBITS, we preserve
+ the sh_link and sh_info fields so that they can be
+ matched up with the original.
+
+ Note: Strictly speaking these assignments are wrong.
+ The sh_link and sh_info fields should point to the
+ relevent sections in the output BFD, which may not be in
+ the same location as they were in the input BFD. But
+ the whole point of this action is to preserve the
+ original values of the sh_link and sh_info fields, so
+ that they can be matched up with the section headers in
+ the original file. So strictly speaking we may be
+ creating an invalid ELF file, but it is only for a file
+ that just contains debug info and only for sections
+ without any contents. */
+ if (oheader->sh_link == 0)
+ oheader->sh_link = iheader->sh_link;
+ if (oheader->sh_info == 0)
+ oheader->sh_info = iheader->sh_info;
+ return TRUE;
+ }
+
+ /* Allow the target a chance to decide how these fields should be set. */
+ if (bed->elf_backend_copy_special_section_fields != NULL
+ && bed->elf_backend_copy_special_section_fields
+ (ibfd, obfd, iheader, oheader))
+ return TRUE;
+
+ /* We have an iheader which might match oheader, and which has non-zero
+ sh_info and/or sh_link fields. Attempt to follow those links and find
+ the section in the output bfd which corresponds to the linked section
+ in the input bfd. */
+ if (iheader->sh_link != SHN_UNDEF)
+ {
+ /* See PR 20931 for a reproducer. */
+ if (iheader->sh_link >= elf_numsections (ibfd))
+ {
+ (* _bfd_error_handler)
+ /* xgettext:c-format */
+ (_("%B: Invalid sh_link field (%d) in section number %d"),
+ ibfd, iheader->sh_link, secnum);
+ return FALSE;
+ }
+
+ sh_link = find_link (obfd, iheaders[iheader->sh_link], iheader->sh_link);
+ if (sh_link != SHN_UNDEF)
+ {
+ oheader->sh_link = sh_link;
+ changed = TRUE;
+ }
+ else
+ /* FIXME: Should we install iheader->sh_link
+ if we could not find a match ? */
+ (* _bfd_error_handler)
+ /* xgettext:c-format */
+ (_("%B: Failed to find link section for section %d"), obfd, secnum);
+ }
+
+ if (iheader->sh_info)
+ {
+ /* The sh_info field can hold arbitrary information, but if the
+ SHF_LINK_INFO flag is set then it should be interpreted as a
+ section index. */
+ if (iheader->sh_flags & SHF_INFO_LINK)
+ {
+ sh_link = find_link (obfd, iheaders[iheader->sh_info],
+ iheader->sh_info);
+ if (sh_link != SHN_UNDEF)
+ oheader->sh_flags |= SHF_INFO_LINK;
+ }
+ else
+ /* No idea what it means - just copy it. */
+ sh_link = iheader->sh_info;
+
+ if (sh_link != SHN_UNDEF)
+ {
+ oheader->sh_info = sh_link;
+ changed = TRUE;
+ }
+ else
+ (* _bfd_error_handler)
+ /* xgettext:c-format */
+ (_("%B: Failed to find info section for section %d"), obfd, secnum);
+ }
+
+ return changed;
+}
+
/* Copy the program header and other data from one object module to
another. */
bfd_boolean
_bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
{
+ const Elf_Internal_Shdr **iheaders = (const Elf_Internal_Shdr **) elf_elfsections (ibfd);
+ Elf_Internal_Shdr **oheaders = elf_elfsections (obfd);
+ const struct elf_backend_data *bed;
+ unsigned int i;
+
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
- || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return TRUE;
if (!elf_flags_init (obfd))
elf_elfheader (obfd)->e_ident[EI_OSABI] =
elf_elfheader (ibfd)->e_ident[EI_OSABI];
+ /* If set, copy the EI_ABIVERSION field. */
+ if (elf_elfheader (ibfd)->e_ident[EI_ABIVERSION])
+ elf_elfheader (obfd)->e_ident[EI_ABIVERSION]
+ = elf_elfheader (ibfd)->e_ident[EI_ABIVERSION];
+
/* Copy object attributes. */
_bfd_elf_copy_obj_attributes (ibfd, obfd);
+
+ if (iheaders == NULL || oheaders == NULL)
+ return TRUE;
+
+ bed = get_elf_backend_data (obfd);
+
+ /* Possibly copy other fields in the section header. */
+ for (i = 1; i < elf_numsections (obfd); i++)
+ {
+ unsigned int j;
+ Elf_Internal_Shdr * oheader = oheaders[i];
+
+ /* Ignore ordinary sections. SHT_NOBITS sections are considered however
+ because of a special case need for generating separate debug info
+ files. See below for more details. */
+ if (oheader == NULL
+ || (oheader->sh_type != SHT_NOBITS
+ && oheader->sh_type < SHT_LOOS))
+ continue;
+
+ /* Ignore empty sections, and sections whose
+ fields have already been initialised. */
+ if (oheader->sh_size == 0
+ || (oheader->sh_info != 0 && oheader->sh_link != 0))
+ continue;
+
+ /* Scan for the matching section in the input bfd.
+ First we try for a direct mapping between the input and output sections. */
+ for (j = 1; j < elf_numsections (ibfd); j++)
+ {
+ const Elf_Internal_Shdr * iheader = iheaders[j];
+
+ if (iheader == NULL)
+ continue;
+
+ if (oheader->bfd_section != NULL
+ && iheader->bfd_section != NULL
+ && iheader->bfd_section->output_section != NULL
+ && iheader->bfd_section->output_section == oheader->bfd_section)
+ {
+ /* We have found a connection from the input section to the
+ output section. Attempt to copy the header fields. If
+ this fails then do not try any further sections - there
+ should only be a one-to-one mapping between input and output. */
+ if (! copy_special_section_fields (ibfd, obfd, iheader, oheader, i))
+ j = elf_numsections (ibfd);
+ break;
+ }
+ }
+
+ if (j < elf_numsections (ibfd))
+ continue;
+
+ /* That failed. So try to deduce the corresponding input section.
+ Unfortunately we cannot compare names as the output string table
+ is empty, so instead we check size, address and type. */
+ for (j = 1; j < elf_numsections (ibfd); j++)
+ {
+ const Elf_Internal_Shdr * iheader = iheaders[j];
+
+ if (iheader == NULL)
+ continue;
+
+ /* Try matching fields in the input section's header.
+ Since --only-keep-debug turns all non-debug sections into
+ SHT_NOBITS sections, the output SHT_NOBITS type matches any
+ input type. */
+ if ((oheader->sh_type == SHT_NOBITS
+ || iheader->sh_type == oheader->sh_type)
+ && (iheader->sh_flags & ~ SHF_INFO_LINK)
+ == (oheader->sh_flags & ~ SHF_INFO_LINK)
+ && iheader->sh_addralign == oheader->sh_addralign
+ && iheader->sh_entsize == oheader->sh_entsize
+ && iheader->sh_size == oheader->sh_size
+ && iheader->sh_addr == oheader->sh_addr
+ && (iheader->sh_info != oheader->sh_info
+ || iheader->sh_link != oheader->sh_link))
+ {
+ if (copy_special_section_fields (ibfd, obfd, iheader, oheader, i))
+ break;
+ }
+ }
+
+ if (j == elf_numsections (ibfd) && oheader->sh_type >= SHT_LOOS)
+ {
+ /* Final attempt. Call the backend copy function
+ with a NULL input section. */
+ if (bed->elf_backend_copy_special_section_fields != NULL)
+ bed->elf_backend_copy_special_section_fields (ibfd, obfd, NULL, oheader);
+ }
+ }
+
return TRUE;
}
break;
}
}
-
-/* Allocate an ELF string table--force the first byte to be zero. */
-
-struct bfd_strtab_hash *
-_bfd_elf_stringtab_init (void)
-{
- struct bfd_strtab_hash *ret;
-
- ret = _bfd_stringtab_init ();
- if (ret != NULL)
- {
- bfd_size_type loc;
-
- loc = _bfd_stringtab_add (ret, "", TRUE, FALSE);
- BFD_ASSERT (loc == 0 || loc == (bfd_size_type) -1);
- if (loc == (bfd_size_type) -1)
- {
- _bfd_stringtab_free (ret);
- ret = NULL;
- }
- }
- return ret;
-}
\f
/* ELF .o/exec file reading */
}
if (sections_being_created [shindex])
{
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%B: warning: loop in section dependencies detected"), abfd);
return FALSE;
}
goto success;
}
- BFD_ASSERT (elf_onesymtab (abfd) == 0);
+ /* PR 18854: A binary might contain more than one symbol table.
+ Unusual, but possible. Warn, but continue. */
+ if (elf_onesymtab (abfd) != 0)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%B: warning: multiple symbol tables detected - ignoring the table in section %u"),
+ abfd, shindex);
+ goto success;
+ }
elf_onesymtab (abfd) = shindex;
- elf_tdata (abfd)->symtab_hdr = *hdr;
- elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->symtab_hdr;
+ elf_symtab_hdr (abfd) = *hdr;
+ elf_elfsections (abfd)[shindex] = hdr = & elf_symtab_hdr (abfd);
abfd->flags |= HAS_SYMS;
/* Sometimes a shared object will map in the symbol table. If
/* Go looking for SHT_SYMTAB_SHNDX too, since if there is one we
can't read symbols without that section loaded as well. It
is most likely specified by the next section header. */
- if (elf_elfsections (abfd)[elf_symtab_shndx (abfd)]->sh_link != shindex)
- {
- unsigned int i, num_sec;
+ {
+ elf_section_list * entry;
+ unsigned int i, num_sec;
- num_sec = elf_numsections (abfd);
- for (i = shindex + 1; i < num_sec; i++)
+ for (entry = elf_symtab_shndx_list (abfd); entry != NULL; entry = entry->next)
+ if (entry->hdr.sh_link == shindex)
+ goto success;
+
+ num_sec = elf_numsections (abfd);
+ for (i = shindex + 1; i < num_sec; i++)
+ {
+ Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
+
+ if (hdr2->sh_type == SHT_SYMTAB_SHNDX
+ && hdr2->sh_link == shindex)
+ break;
+ }
+
+ if (i == num_sec)
+ for (i = 1; i < shindex; i++)
{
Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
+
if (hdr2->sh_type == SHT_SYMTAB_SHNDX
&& hdr2->sh_link == shindex)
break;
}
- if (i == num_sec)
- for (i = 1; i < shindex; i++)
- {
- Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i];
- if (hdr2->sh_type == SHT_SYMTAB_SHNDX
- && hdr2->sh_link == shindex)
- break;
- }
- if (i != shindex)
- ret = bfd_section_from_shdr (abfd, i);
- }
- goto success;
+
+ if (i != shindex)
+ ret = bfd_section_from_shdr (abfd, i);
+ /* else FIXME: we have failed to find the symbol table - should we issue an error ? */
+ goto success;
+ }
case SHT_DYNSYM: /* A dynamic symbol table. */
if (elf_dynsymtab (abfd) == shindex)
goto success;
}
- BFD_ASSERT (elf_dynsymtab (abfd) == 0);
+ /* PR 18854: A binary might contain more than one dynamic symbol table.
+ Unusual, but possible. Warn, but continue. */
+ if (elf_dynsymtab (abfd) != 0)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%B: warning: multiple dynamic symbol tables detected - ignoring the table in section %u"),
+ abfd, shindex);
+ goto success;
+ }
elf_dynsymtab (abfd) = shindex;
elf_tdata (abfd)->dynsymtab_hdr = *hdr;
elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->dynsymtab_hdr;
goto success;
case SHT_SYMTAB_SHNDX: /* Symbol section indices when >64k sections. */
- if (elf_symtab_shndx (abfd) == shindex)
- goto success;
+ {
+ elf_section_list * entry;
- BFD_ASSERT (elf_symtab_shndx (abfd) == 0);
- elf_symtab_shndx (abfd) = shindex;
- elf_tdata (abfd)->symtab_shndx_hdr = *hdr;
- elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->symtab_shndx_hdr;
- goto success;
+ for (entry = elf_symtab_shndx_list (abfd); entry != NULL; entry = entry->next)
+ if (entry->ndx == shindex)
+ goto success;
+
+ entry = bfd_alloc (abfd, sizeof * entry);
+ if (entry == NULL)
+ goto fail;
+ entry->ndx = shindex;
+ entry->hdr = * hdr;
+ entry->next = elf_symtab_shndx_list (abfd);
+ elf_symtab_shndx_list (abfd) = entry;
+ elf_elfsections (abfd)[shindex] = & entry->hdr;
+ goto success;
+ }
case SHT_STRTAB: /* A string table. */
if (hdr->bfd_section != NULL)
Elf_Internal_Shdr *hdr2, **p_hdr;
unsigned int num_sec = elf_numsections (abfd);
struct bfd_elf_section_data *esdt;
- bfd_size_type amt;
if (hdr->sh_entsize
!= (bfd_size_type) (hdr->sh_type == SHT_REL
/* Check for a bogus link to avoid crashing. */
if (hdr->sh_link >= num_sec)
{
- ((*_bfd_error_handler)
- (_("%B: invalid link %lu for reloc section %s (index %u)"),
- abfd, hdr->sh_link, name, shindex));
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%B: invalid link %lu for reloc section %s (index %u)"),
+ abfd, hdr->sh_link, name, shindex);
ret = _bfd_elf_make_section_from_shdr (abfd, hdr, name,
shindex);
goto success;
/* PR 17512: file: 0b4f81b7. */
if (*p_hdr != NULL)
goto fail;
- amt = sizeof (*hdr2);
- hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt);
+ hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, sizeof (*hdr2));
if (hdr2 == NULL)
goto fail;
*hdr2 = *hdr;
if ((hdr->sh_flags & SHF_ALLOC) != 0)
/* FIXME: How to properly handle allocated section reserved
for applications? */
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: don't know how to handle allocated, application "
"specific section `%s' [0x%8x]"),
abfd, name, hdr->sh_type);
else if (hdr->sh_type >= SHT_LOPROC
&& hdr->sh_type <= SHT_HIPROC)
/* FIXME: We should handle this section. */
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: don't know how to handle processor specific section "
"`%s' [0x%8x]"),
abfd, name, hdr->sh_type);
/* 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)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: don't know how to handle OS specific section "
"`%s' [0x%8x]"),
abfd, name, hdr->sh_type);
}
else
/* FIXME: We should handle this section. */
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: don't know how to handle section `%s' [0x%8x]"),
abfd, name, hdr->sh_type);
return elf_section_data (sec)->rela.hdr;
}
+static bfd_boolean
+_bfd_elf_set_reloc_sh_name (bfd *abfd,
+ Elf_Internal_Shdr *rel_hdr,
+ const char *sec_name,
+ bfd_boolean use_rela_p)
+{
+ char *name = (char *) bfd_alloc (abfd,
+ sizeof ".rela" + strlen (sec_name));
+ if (name == NULL)
+ return FALSE;
+
+ sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", sec_name);
+ rel_hdr->sh_name =
+ (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), name,
+ FALSE);
+ if (rel_hdr->sh_name == (unsigned int) -1)
+ return FALSE;
+
+ return TRUE;
+}
+
/* Allocate and initialize a section-header for a new reloc section,
containing relocations against ASECT. It is stored in RELDATA. If
USE_RELA_P is TRUE, we use RELA relocations; otherwise, we use REL
static bfd_boolean
_bfd_elf_init_reloc_shdr (bfd *abfd,
struct bfd_elf_section_reloc_data *reldata,
- asection *asect,
- bfd_boolean use_rela_p)
+ const char *sec_name,
+ bfd_boolean use_rela_p,
+ bfd_boolean delay_st_name_p)
{
Elf_Internal_Shdr *rel_hdr;
- char *name;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
- bfd_size_type amt;
- amt = sizeof (Elf_Internal_Shdr);
BFD_ASSERT (reldata->hdr == NULL);
- rel_hdr = bfd_zalloc (abfd, amt);
+ rel_hdr = bfd_zalloc (abfd, sizeof (*rel_hdr));
reldata->hdr = rel_hdr;
- amt = sizeof ".rela" + strlen (asect->name);
- name = (char *) bfd_alloc (abfd, amt);
- if (name == NULL)
- return FALSE;
- sprintf (name, "%s%s", use_rela_p ? ".rela" : ".rel", asect->name);
- rel_hdr->sh_name =
- (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), name,
- FALSE);
- if (rel_hdr->sh_name == (unsigned int) -1)
+ if (delay_st_name_p)
+ rel_hdr->sh_name = (unsigned int) -1;
+ else if (!_bfd_elf_set_reloc_sh_name (abfd, rel_hdr, sec_name,
+ use_rela_p))
return FALSE;
rel_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL;
rel_hdr->sh_entsize = (use_rela_p
Elf_Internal_Shdr *this_hdr;
unsigned int sh_type;
const char *name = asect->name;
+ bfd_boolean delay_st_name_p = FALSE;
if (arg->failed)
{
this_hdr = &esd->this_hdr;
- /* For linking, compress DWARF debug sections with names: .debug_*. */
- if (arg->link_info
- && (arg->link_info->compress_debug & COMPRESS_DEBUG)
- && (asect->flags & SEC_DEBUGGING)
- && name[1] == 'd'
- && name[6] == '_')
+ if (arg->link_info)
{
- /* Set SEC_ELF_COMPRESS to indicate this section should be
- compressed. */
- asect->flags |= SEC_ELF_COMPRESS;
+ /* ld: compress DWARF debug sections with names: .debug_*. */
+ if ((arg->link_info->compress_debug & COMPRESS_DEBUG)
+ && (asect->flags & SEC_DEBUGGING)
+ && name[1] == 'd'
+ && name[6] == '_')
+ {
+ /* Set SEC_ELF_COMPRESS to indicate this section should be
+ compressed. */
+ asect->flags |= SEC_ELF_COMPRESS;
- if (arg->link_info->compress_debug != COMPRESS_DEBUG_GABI_ZLIB)
+ /* If this section will be compressed, delay adding section
+ name to section name section after it is compressed in
+ _bfd_elf_assign_file_positions_for_non_load. */
+ delay_st_name_p = TRUE;
+ }
+ }
+ else if ((asect->flags & SEC_ELF_RENAME))
+ {
+ /* objcopy: rename output DWARF debug section. */
+ if ((abfd->flags & (BFD_DECOMPRESS | BFD_COMPRESS_GABI)))
+ {
+ /* When we decompress or compress with SHF_COMPRESSED,
+ convert section name from .zdebug_* to .debug_* if
+ needed. */
+ if (name[1] == 'z')
+ {
+ char *new_name = convert_zdebug_to_debug (abfd, name);
+ if (new_name == NULL)
+ {
+ arg->failed = TRUE;
+ return;
+ }
+ name = new_name;
+ }
+ }
+ else if (asect->compress_status == COMPRESS_SECTION_DONE)
{
- /* If SHF_COMPRESSED isn't used, rename compressed DWARF
- debug section to .zdebug_*. */
- unsigned int len = strlen (name);
- char *new_name = bfd_alloc (abfd, len + 2);
+ /* PR binutils/18087: Compression does not always make a
+ section smaller. So only rename the section when
+ compression has actually taken place. If input section
+ name is .zdebug_*, we should never compress it again. */
+ char *new_name = convert_debug_to_zdebug (abfd, name);
if (new_name == NULL)
{
arg->failed = TRUE;
return;
}
- new_name[0] = '.';
- new_name[1] = 'z';
- memcpy (new_name + 2, name + 1, len);
- bfd_rename_section (abfd, asect, new_name);
- name = asect->name;
+ BFD_ASSERT (name[1] != 'z');
+ name = new_name;
}
}
- this_hdr->sh_name = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
- name, FALSE);
- if (this_hdr->sh_name == (unsigned int) -1)
+ if (delay_st_name_p)
+ this_hdr->sh_name = (unsigned int) -1;
+ else
{
- arg->failed = TRUE;
- return;
+ this_hdr->sh_name
+ = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
+ name, FALSE);
+ if (this_hdr->sh_name == (unsigned int) -1)
+ {
+ arg->failed = TRUE;
+ return;
+ }
}
/* Don't clear sh_flags. Assembler may set additional bits. */
/* PR 17512: file: 0eb809fe, 8b0535ee. */
if (asect->alignment_power >= (sizeof (bfd_vma) * 8) - 1)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: error: Alignment power %d of section `%A' is too big"),
abfd, asect, asect->alignment_power);
arg->failed = TRUE;
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)
+ _bfd_error_handler
(_("warning: section `%A' type changed to PROGBITS"), asect);
this_hdr->sh_type = sh_type;
}
break;
case SHT_STRTAB:
- case SHT_INIT_ARRAY:
- case SHT_FINI_ARRAY:
- case SHT_PREINIT_ARRAY:
case SHT_NOTE:
case SHT_NOBITS:
case SHT_PROGBITS:
break;
+ case SHT_INIT_ARRAY:
+ case SHT_FINI_ARRAY:
+ case SHT_PREINIT_ARRAY:
+ this_hdr->sh_entsize = bed->s->arch_size / 8;
+ break;
+
case SHT_HASH:
this_hdr->sh_entsize = bed->s->sizeof_hash_entry;
break;
{
this_hdr->sh_flags |= SHF_MERGE;
this_hdr->sh_entsize = asect->entsize;
- if ((asect->flags & SEC_STRINGS) != 0)
- this_hdr->sh_flags |= SHF_STRINGS;
}
+ if ((asect->flags & SEC_STRINGS) != 0)
+ this_hdr->sh_flags |= SHF_STRINGS;
if ((asect->flags & SEC_GROUP) == 0 && elf_group_name (asect) != NULL)
this_hdr->sh_flags |= SHF_GROUP;
if ((asect->flags & SEC_THREAD_LOCAL) != 0)
if (arg->link_info
/* Do the normal setup if we wouldn't create any sections here. */
&& esd->rel.count + esd->rela.count > 0
- && (arg->link_info->relocatable || arg->link_info->emitrelocations))
+ && (bfd_link_relocatable (arg->link_info)
+ || arg->link_info->emitrelocations))
{
if (esd->rel.count && esd->rel.hdr == NULL
- && !_bfd_elf_init_reloc_shdr (abfd, &esd->rel, asect, FALSE))
+ && !_bfd_elf_init_reloc_shdr (abfd, &esd->rel, name, FALSE,
+ delay_st_name_p))
{
arg->failed = TRUE;
return;
}
if (esd->rela.count && esd->rela.hdr == NULL
- && !_bfd_elf_init_reloc_shdr (abfd, &esd->rela, asect, TRUE))
+ && !_bfd_elf_init_reloc_shdr (abfd, &esd->rela, name, TRUE,
+ delay_st_name_p))
{
arg->failed = TRUE;
return;
else if (!_bfd_elf_init_reloc_shdr (abfd,
(asect->use_rela_p
? &esd->rela : &esd->rel),
- asect,
- asect->use_rela_p))
+ name,
+ asect->use_rela_p,
+ delay_st_name_p))
arg->failed = TRUE;
}
/* The ELF backend linker sets sh_info to -2 when the group
signature symbol is global, and thus the index can't be
set until all local symbols are output. */
- asection *igroup = elf_sec_group (elf_next_in_group (sec));
- struct bfd_elf_section_data *sec_data = elf_section_data (igroup);
- unsigned long symndx = sec_data->this_hdr.sh_info;
- unsigned long extsymoff = 0;
+ asection *igroup;
+ struct bfd_elf_section_data *sec_data;
+ unsigned long symndx;
+ unsigned long extsymoff;
struct elf_link_hash_entry *h;
+ /* The point of this little dance to the first SHF_GROUP section
+ then back to the SHT_GROUP section is that this gets us to
+ the SHT_GROUP in the input object. */
+ igroup = elf_sec_group (elf_next_in_group (sec));
+ sec_data = elf_section_data (igroup);
+ symndx = sec_data->this_hdr.sh_info;
+ extsymoff = 0;
if (!elf_bad_symtab (igroup->owner))
{
Elf_Internal_Shdr *symtab_hdr;
{
struct elf_obj_tdata *t = elf_tdata (abfd);
asection *sec;
- unsigned int section_number, secn;
+ unsigned int section_number;
Elf_Internal_Shdr **i_shdrp;
struct bfd_elf_section_data *d;
bfd_boolean need_symtab;
_bfd_elf_strtab_clear_all_refs (elf_shstrtab (abfd));
/* SHT_GROUP sections are in relocatable files only. */
- if (link_info == NULL || link_info->relocatable)
+ if (link_info == NULL || bfd_link_relocatable (link_info))
{
+ size_t reloc_count = 0;
+
/* Put SHT_GROUP sections first. */
for (sec = abfd->sections; sec != NULL; sec = sec->next)
{
else
d->this_idx = section_number++;
}
+
+ /* Count relocations. */
+ reloc_count += sec->reloc_count;
}
+
+ /* Clear HAS_RELOC if there are no relocations. */
+ if (reloc_count == 0)
+ abfd->flags &= ~HAS_RELOC;
}
for (sec = abfd->sections; sec; sec = sec->next)
if (d->this_hdr.sh_type != SHT_GROUP)
d->this_idx = section_number++;
- _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->this_hdr.sh_name);
+ if (d->this_hdr.sh_name != (unsigned int) -1)
+ _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->this_hdr.sh_name);
if (d->rel.hdr)
{
d->rel.idx = section_number++;
- _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel.hdr->sh_name);
+ if (d->rel.hdr->sh_name != (unsigned int) -1)
+ _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel.hdr->sh_name);
}
else
d->rel.idx = 0;
if (d->rela.hdr)
{
d->rela.idx = section_number++;
- _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rela.hdr->sh_name);
+ if (d->rela.hdr->sh_name != (unsigned int) -1)
+ _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rela.hdr->sh_name);
}
else
d->rela.idx = 0;
}
- elf_shstrtab_sec (abfd) = section_number++;
- _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->shstrtab_hdr.sh_name);
- elf_elfheader (abfd)->e_shstrndx = elf_shstrtab_sec (abfd);
-
need_symtab = (bfd_get_symcount (abfd) > 0
|| (link_info == NULL
&& ((abfd->flags & (EXEC_P | DYNAMIC | HAS_RELOC))
_bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name);
if (section_number > ((SHN_LORESERVE - 2) & 0xFFFF))
{
- elf_symtab_shndx (abfd) = section_number++;
- t->symtab_shndx_hdr.sh_name
+ elf_section_list * entry;
+
+ BFD_ASSERT (elf_symtab_shndx_list (abfd) == NULL);
+
+ entry = bfd_zalloc (abfd, sizeof * entry);
+ entry->ndx = section_number++;
+ elf_symtab_shndx_list (abfd) = entry;
+ entry->hdr.sh_name
= (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
".symtab_shndx", FALSE);
- if (t->symtab_shndx_hdr.sh_name == (unsigned int) -1)
+ if (entry->hdr.sh_name == (unsigned int) -1)
return FALSE;
}
elf_strtab_sec (abfd) = section_number++;
_bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name);
}
+ elf_shstrtab_sec (abfd) = section_number++;
+ _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->shstrtab_hdr.sh_name);
+ elf_elfheader (abfd)->e_shstrndx = elf_shstrtab_sec (abfd);
+
if (section_number >= SHN_LORESERVE)
{
+ /* xgettext:c-format */
_bfd_error_handler (_("%B: too many sections: %u"),
abfd, section_number);
return FALSE;
}
- _bfd_elf_strtab_finalize (elf_shstrtab (abfd));
- t->shstrtab_hdr.sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
-
elf_numsections (abfd) = section_number;
elf_elfheader (abfd)->e_shnum = section_number;
i_shdrp[elf_onesymtab (abfd)] = &t->symtab_hdr;
if (elf_numsections (abfd) > (SHN_LORESERVE & 0xFFFF))
{
- i_shdrp[elf_symtab_shndx (abfd)] = &t->symtab_shndx_hdr;
- t->symtab_shndx_hdr.sh_link = elf_onesymtab (abfd);
+ elf_section_list * entry = elf_symtab_shndx_list (abfd);
+ BFD_ASSERT (entry != NULL);
+ i_shdrp[entry->ndx] = & entry->hdr;
+ entry->hdr.sh_link = elf_onesymtab (abfd);
}
i_shdrp[elf_strtab_sec (abfd)] = &t->strtab_hdr;
t->symtab_hdr.sh_link = elf_strtab_sec (abfd);
if (discarded_section (s))
{
asection *kept;
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: sh_link of section `%A' points to discarded section `%A' of `%B'"),
abfd, d->this_hdr.bfd_section,
s, s->owner);
/* Handle objcopy. */
if (s->output_section == NULL)
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: sh_link of section `%A' points to removed section `%A' of `%B'"),
abfd, d->this_hdr.bfd_section, s, s->owner);
bfd_set_error (bfd_error_bad_value);
= get_elf_backend_data (abfd);
if (bed->link_order_error_handler)
bed->link_order_error_handler
+ /* xgettext:c-format */
(_("%B: warning: sh_link not set for section `%A'"),
abfd, sec);
}
}
}
- for (secn = 1; secn < section_number; ++secn)
- i_shdrp[secn]->sh_name = _bfd_elf_strtab_offset (elf_shstrtab (abfd),
- i_shdrp[secn]->sh_name);
+ /* Delay setting sh_name to _bfd_elf_write_object_contents so that
+ _bfd_elf_assign_file_positions_for_non_load can convert DWARF
+ debug section name from .debug_* to .zdebug_* if needed. */
+
return TRUE;
}
|| bfd_is_com_section (bfd_get_section (sym)));
}
+/* Filter global symbols of ABFD to include in the import library. All
+ SYMCOUNT symbols of ABFD can be examined from their pointers in
+ SYMS. Pointers of symbols to keep should be stored contiguously at
+ the beginning of that array.
+
+ Returns the number of symbols to keep. */
+
+unsigned int
+_bfd_elf_filter_global_symbols (bfd *abfd, struct bfd_link_info *info,
+ asymbol **syms, long symcount)
+{
+ long src_count, dst_count = 0;
+
+ for (src_count = 0; src_count < symcount; src_count++)
+ {
+ asymbol *sym = syms[src_count];
+ char *name = (char *) bfd_asymbol_name (sym);
+ struct bfd_link_hash_entry *h;
+
+ if (!sym_is_global (abfd, sym))
+ continue;
+
+ h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, FALSE);
+ if (h == NULL)
+ continue;
+ if (h->type != bfd_link_hash_defined && h->type != bfd_link_hash_defweak)
+ continue;
+ if (h->linker_def || h->ldscript_def)
+ continue;
+
+ syms[dst_count++] = sym;
+ }
+
+ syms[dst_count] = NULL;
+
+ return dst_count;
+}
+
/* Don't output section symbols for sections that are not going to be
output, that are duplicates or there is no BFD section. */
unsigned int num_globals = 0;
unsigned int num_locals2 = 0;
unsigned int num_globals2 = 0;
- int max_index = 0;
+ unsigned int max_index = 0;
unsigned int idx;
asection *asect;
asymbol **new_syms;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct fake_section_arg fsargs;
bfd_boolean failed;
- struct bfd_strtab_hash *strtab = NULL;
+ struct elf_strtab_hash *strtab = NULL;
Elf_Internal_Shdr *shstrtab_hdr;
bfd_boolean need_symtab;
shstrtab_hdr = &elf_tdata (abfd)->shstrtab_hdr;
/* sh_name was set in prep_headers. */
shstrtab_hdr->sh_type = SHT_STRTAB;
- shstrtab_hdr->sh_flags = 0;
+ shstrtab_hdr->sh_flags = bed->elf_strtab_flags;
shstrtab_hdr->sh_addr = 0;
- shstrtab_hdr->sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
+ /* sh_size is set in _bfd_elf_assign_file_positions_for_non_load. */
shstrtab_hdr->sh_entsize = 0;
shstrtab_hdr->sh_link = 0;
shstrtab_hdr->sh_info = 0;
- /* sh_offset is set in assign_file_positions_except_relocs. */
+ /* sh_offset is set in _bfd_elf_assign_file_positions_for_non_load. */
shstrtab_hdr->sh_addralign = 1;
if (!assign_file_positions_except_relocs (abfd, link_info))
off = elf_next_file_pos (abfd);
- hdr = &elf_tdata (abfd)->symtab_hdr;
+ hdr = & elf_symtab_hdr (abfd);
off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
- hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
- if (hdr->sh_size != 0)
- off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
+ if (elf_symtab_shndx_list (abfd) != NULL)
+ {
+ hdr = & elf_symtab_shndx_list (abfd)->hdr;
+ if (hdr->sh_size != 0)
+ off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
+ /* FIXME: What about other symtab_shndx sections in the list ? */
+ }
hdr = &elf_tdata (abfd)->strtab_hdr;
off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
/* Now that we know where the .strtab section goes, write it
out. */
if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
- || ! _bfd_stringtab_emit (abfd, strtab))
+ || ! _bfd_elf_strtab_emit (abfd, strtab))
return FALSE;
- _bfd_stringtab_free (strtab);
+ _bfd_elf_strtab_free (strtab);
}
abfd->output_has_begun = TRUE;
}
(*m)->count = new_count;
- if (remove_empty_load && (*m)->p_type == PT_LOAD && (*m)->count == 0)
+ if (remove_empty_load
+ && (*m)->p_type == PT_LOAD
+ && (*m)->count == 0
+ && !(*m)->includes_phdrs)
*m = (*m)->next;
else
m = &(*m)->next;
asection *dynsec, *eh_frame_hdr;
bfd_size_type amt;
bfd_vma addr_mask, wrap_to = 0;
+ bfd_boolean linker_created_pt_phdr_segment = FALSE;
/* Select the allocated sections, and sort them. */
m->p_flags = PF_R | PF_X;
m->p_flags_valid = 1;
m->includes_phdrs = 1;
-
+ linker_created_pt_phdr_segment = TRUE;
*pm = m;
pm = &m->next;
|| ((sections[0]->lma & addr_mask) % maxpagesize
< phdr_size % maxpagesize)
|| (sections[0]->lma & addr_mask & -maxpagesize) < wrap_to)
- phdr_in_segment = FALSE;
+ {
+ /* PR 20815: The ELF standard says that a PT_PHDR segment, if
+ present, must be included as part of the memory image of the
+ program. Ie it must be part of a PT_LOAD segment as well.
+ If we have had to create our own PT_PHDR segment, but it is
+ not going to be covered by the first PT_LOAD segment, then
+ force the inclusion if we can... */
+ if ((abfd->flags & D_PAGED) != 0
+ && linker_created_pt_phdr_segment)
+ phdr_in_segment = TRUE;
+ else
+ phdr_in_segment = FALSE;
+ }
}
for (i = 0, hdrpp = sections; i < count; i++, hdrpp++)
new_segment = TRUE;
}
else if ((last_hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0
- && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0)
+ && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0
+ && ((abfd->flags & D_PAGED) == 0
+ || (((last_hdr->lma + last_size - 1) & -maxpagesize)
+ != (hdr->lma & -maxpagesize))))
{
- /* 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. */
+ /* We don't want to put a loaded section after a
+ nonloaded (ie. bss style) section in the same segment
+ as that will force the non-loaded section to be loaded.
+ Consider .tbss sections as loaded for this purpose.
+ However, like the writable/non-writable case below,
+ if they are on the same page then they must be put
+ in the same segment. */
new_segment = TRUE;
}
else if ((abfd->flags & D_PAGED) == 0)
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;
}
Elf_Internal_Phdr *p;
file_ptr off;
bfd_size_type maxpagesize;
+ unsigned int pt_load_count = 0;
unsigned int alloc;
unsigned int i, j;
bfd_vma header_pad = 0;
maxpagesize = m->p_align;
p->p_align = maxpagesize;
+ pt_load_count += 1;
}
else if (m->p_align_valid)
p->p_align = m->p_align;
}
off_adjust = vma_page_aligned_bias (p->p_vaddr, off, align);
+
+ /* Broken hardware and/or kernel require that files do not
+ map the same page with different permissions on some hppa
+ processors. */
+ if (pt_load_count > 1
+ && bed->no_page_alias
+ && (off & (maxpagesize - 1)) != 0
+ && (off & -maxpagesize) == ((off + off_adjust) & -maxpagesize))
+ off_adjust += maxpagesize;
off += off_adjust;
if (no_contents)
{
p->p_memsz = bed->s->sizeof_ehdr;
if (m->count > 0)
{
- if (p->p_vaddr < (bfd_vma) off)
+ if (p->p_vaddr < (bfd_vma) off
+ || (!m->p_paddr_valid
+ && p->p_paddr < (bfd_vma) off))
{
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%B: Not enough room for program headers, try linking with -N"),
abfd);
bfd_set_error (bfd_error_bad_value);
&& (s_start < p_end
|| p_end < p_start))
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: section %A lma %#lx adjusted to %#lx"), abfd, sec,
(unsigned long) s_start, (unsigned long) p_end);
adjust = 0;
if (!ELF_SECTION_IN_SEGMENT_1 (this_hdr, p, check_vma, 0)
&& !ELF_TBSS_SPECIAL (this_hdr, p))
{
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: section `%A' can't be allocated in segment %d"),
abfd, sec, j);
print_segment_map (m);
else if ((hdr->sh_flags & SHF_ALLOC) != 0)
{
if (hdr->sh_size != 0)
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: warning: allocated section `%s' not in segment"),
abfd,
(hdr->bfd_section == NULL
&& (hdr->bfd_section->flags & SEC_ELF_COMPRESS))
/* Compress DWARF debug sections. */
|| hdr == i_shdrpp[elf_onesymtab (abfd)]
- || hdr == i_shdrpp[elf_symtab_shndx (abfd)]
- || hdr == i_shdrpp[elf_strtab_sec (abfd)])
+ || (elf_symtab_shndx_list (abfd) != NULL
+ && hdr == i_shdrpp[elf_symtab_shndx_list (abfd)->ndx])
+ || hdr == i_shdrpp[elf_strtab_sec (abfd)]
+ || hdr == i_shdrpp[elf_shstrtab_sec (abfd)])
hdr->sh_offset = -1;
else
off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
if (!m->p_align_valid)
p->p_align = 1;
if (!m->p_flags_valid)
- p->p_flags = (lp->p_flags & ~PF_W);
+ p->p_flags = PF_R;
}
else
{
else if (m->count != 0)
{
unsigned int i;
+
if (p->p_type != PT_LOAD
&& (p->p_type != PT_NOTE
|| bfd_get_format (abfd) != bfd_core))
{
+ /* A user specified segment layout may include a PHDR
+ segment that overlaps with a LOAD segment... */
+ if (p->p_type == PT_PHDR)
+ {
+ m->count = 0;
+ continue;
+ }
+
if (m->includes_filehdr || m->includes_phdrs)
{
- /* PR 17512: file: 2195325e. */
- (*_bfd_error_handler)
- (_("%B: warning: non-load segment includes file header and/or program header"),
- abfd);
+ /* PR 17512: file: 2195325e. */
+ _bfd_error_handler
+ (_("%B: error: non-load segment %d includes file header and/or program header"),
+ abfd, (int)(p - phdrs));
return FALSE;
}
return TRUE;
}
+static elf_section_list *
+find_section_in_list (unsigned int i, elf_section_list * list)
+{
+ for (;list != NULL; list = list->next)
+ if (list->ndx == i)
+ break;
+ return list;
+}
+
/* 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.
&& (hdr->bfd_section->flags & SEC_ELF_COMPRESS))
/* Compress DWARF debug sections. */
|| i == elf_onesymtab (abfd)
- || i == elf_symtab_shndx (abfd)
- || i == elf_strtab_sec (abfd))
+ || (elf_symtab_shndx_list (abfd) != NULL
+ && hdr == i_shdrpp[elf_symtab_shndx_list (abfd)->ndx])
+ || i == elf_strtab_sec (abfd)
+ || i == elf_shstrtab_sec (abfd))
{
hdr->sh_offset = -1;
}
}
/* Set e_type in ELF header to ET_EXEC for -pie -Ttext-segment=. */
- if (link_info != NULL
- && link_info->executable
- && link_info->shared)
+ if (link_info != NULL && bfd_link_pie (link_info))
{
unsigned int num_segments = elf_elfheader (abfd)->e_phnum;
Elf_Internal_Phdr *segment = elf_tdata (abfd)->phdr;
/* Write out the program headers. */
alloc = elf_program_header_size (abfd) / bed->s->sizeof_phdr;
+
+ /* Sort the program headers into the ordering required by the ELF standard. */
+ if (alloc == 0)
+ return TRUE;
+
+ /* PR ld/20815 - Check that the program header segment, if present, will
+ be loaded into memory. FIXME: The check below is not sufficient as
+ really all PT_LOAD segments should be checked before issuing an error
+ message. Plus the PHDR segment does not have to be the first segment
+ in the program header table. But this version of the check should
+ catch all real world use cases.
+
+ FIXME: We used to have code here to sort the PT_LOAD segments into
+ ascending order, as per the ELF spec. But this breaks some programs,
+ including the Linux kernel. But really either the spec should be
+ changed or the programs updated. */
+ if (alloc > 1
+ && tdata->phdr[0].p_type == PT_PHDR
+ && ! bed->elf_backend_allow_non_load_phdr (abfd, tdata->phdr, alloc)
+ && tdata->phdr[1].p_type == PT_LOAD
+ && (tdata->phdr[1].p_vaddr > tdata->phdr[0].p_vaddr
+ || (tdata->phdr[1].p_vaddr + tdata->phdr[1].p_memsz)
+ < (tdata->phdr[0].p_vaddr + tdata->phdr[0].p_memsz)))
+ {
+ /* The fix for this error is usually to edit the linker script being
+ used and set up the program headers manually. Either that or
+ leave room for the headers at the start of the SECTIONS. */
+ _bfd_error_handler (_("\
+%B: error: PHDR segment not covered by LOAD segment"),
+ abfd);
+ return FALSE;
+ }
+
if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0
|| bed->s->write_out_phdrs (abfd, tdata->phdr, alloc) != 0)
return FALSE;
{
file_ptr off;
Elf_Internal_Shdr **shdrpp, **end_shdrpp;
+ Elf_Internal_Shdr *shdrp;
Elf_Internal_Ehdr *i_ehdrp;
const struct elf_backend_data *bed;
end_shdrpp = shdrpp + elf_numsections (abfd);
for (shdrpp++; shdrpp < end_shdrpp; shdrpp++)
{
- Elf_Internal_Shdr *shdrp;
-
shdrp = *shdrpp;
if (shdrp->sh_offset == -1)
{
+ asection *sec = shdrp->bfd_section;
bfd_boolean is_rel = (shdrp->sh_type == SHT_REL
|| shdrp->sh_type == SHT_RELA);
if (is_rel
- || (shdrp->bfd_section != NULL
- && (shdrp->bfd_section->flags & SEC_ELF_COMPRESS)))
+ || (sec != NULL && (sec->flags & SEC_ELF_COMPRESS)))
{
if (!is_rel)
{
+ const char *name = sec->name;
+ struct bfd_elf_section_data *d;
+
/* Compress DWARF debug sections. */
- if (!bfd_compress_section (abfd, shdrp->bfd_section,
+ if (!bfd_compress_section (abfd, sec,
shdrp->contents))
return FALSE;
+
+ if (sec->compress_status == COMPRESS_SECTION_DONE
+ && (abfd->flags & BFD_COMPRESS_GABI) == 0)
+ {
+ /* If section is compressed with zlib-gnu, convert
+ section name from .debug_* to .zdebug_*. */
+ char *new_name
+ = convert_debug_to_zdebug (abfd, name);
+ if (new_name == NULL)
+ return FALSE;
+ name = new_name;
+ }
+ /* Add section name to section name section. */
+ if (shdrp->sh_name != (unsigned int) -1)
+ abort ();
+ shdrp->sh_name
+ = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd),
+ name, FALSE);
+ d = elf_section_data (sec);
+
+ /* Add reloc section name to section name section. */
+ if (d->rel.hdr
+ && !_bfd_elf_set_reloc_sh_name (abfd,
+ d->rel.hdr,
+ name, FALSE))
+ return FALSE;
+ if (d->rela.hdr
+ && !_bfd_elf_set_reloc_sh_name (abfd,
+ d->rela.hdr,
+ name, TRUE))
+ return FALSE;
+
/* Update section size and contents. */
- shdrp->sh_size = shdrp->bfd_section->size;
- shdrp->contents = shdrp->bfd_section->contents;
+ shdrp->sh_size = sec->size;
+ shdrp->contents = sec->contents;
shdrp->bfd_section->contents = NULL;
}
off = _bfd_elf_assign_file_position_for_section (shdrp,
}
}
-/* Place the section headers. */
+ /* Place section name section after DWARF debug sections have been
+ compressed. */
+ _bfd_elf_strtab_finalize (elf_shstrtab (abfd));
+ shdrp = &elf_tdata (abfd)->shstrtab_hdr;
+ shdrp->sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd));
+ off = _bfd_elf_assign_file_position_for_section (shdrp, off, TRUE);
+
+ /* Place the section headers. */
i_ehdrp = elf_elfheader (abfd);
bed = get_elf_backend_data (abfd);
off = align_file_position (off, 1 << bed->s->log_file_align);
num_sec = elf_numsections (abfd);
for (count = 1; count < num_sec; count++)
{
+ i_shdrp[count]->sh_name
+ = _bfd_elf_strtab_offset (elf_shstrtab (abfd),
+ i_shdrp[count]->sh_name);
if (bed->elf_backend_section_processing)
(*bed->elf_backend_section_processing) (abfd, i_shdrp[count]);
if (i_shdrp[count]->contents)
{
/* This case can occur when using --strip-symbol on a symbol
which is used in a relocation entry. */
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: symbol `%s' required but not present"),
abfd, bfd_asymbol_name (asym_ptr));
bfd_set_error (bfd_error_no_symbols);
something. They are allowed by the ELF spec however, so only
a warning is produced. */
if (segment->p_type == PT_LOAD)
- (*_bfd_error_handler) (_("\
+ _bfd_error_handler (_("\
%B: warning: Empty loadable segment detected, is this intentional ?"),
- ibfd);
+ ibfd);
map->count = 0;
*pointer_to_map = map;
first_matching_lma = TRUE;
first_suggested_lma = TRUE;
- for (section = ibfd->sections;
+ for (section = first_section, j = 0;
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))
{
{
/* PR 17512: file: f17299af. */
if (segment->p_align > (bfd_vma) 1 << ((sizeof (bfd_vma) * 8) - 2))
- (*_bfd_error_handler) (_("\
+ /* xgettext:c-format */
+ _bfd_error_handler (_("\
%B: warning: segment alignment of 0x%llx is too large"),
- ibfd, (long long) segment->p_align);
+ ibfd, (long long) segment->p_align);
else
maxpagesize = segment->p_align;
}
{
Elf_Internal_Shdr *ihdr, *ohdr;
- bfd_boolean final_link = link_info != NULL && !link_info->relocatable;
+ bfd_boolean final_link = (link_info != NULL
+ && !bfd_link_relocatable (link_info));
if (ibfd->xvec->flavour != bfd_target_elf_flavour
|| obfd->xvec->flavour != bfd_target_elf_flavour)
shndx = MAP_STRTAB;
else if (shndx == elf_shstrtab_sec (ibfd))
shndx = MAP_SHSTRTAB;
- else if (shndx == elf_symtab_shndx (ibfd))
+ else if (find_section_in_list (shndx, elf_symtab_shndx_list (ibfd)))
shndx = MAP_SYM_SHNDX;
osym->internal_elf_sym.st_shndx = shndx;
}
static bfd_boolean
swap_out_syms (bfd *abfd,
- struct bfd_strtab_hash **sttp,
+ struct elf_strtab_hash **sttp,
int relocatable_p)
{
const struct elf_backend_data *bed;
int symcount;
asymbol **syms;
- struct bfd_strtab_hash *stt;
+ struct elf_strtab_hash *stt;
Elf_Internal_Shdr *symtab_hdr;
Elf_Internal_Shdr *symtab_shndx_hdr;
Elf_Internal_Shdr *symstrtab_hdr;
+ struct elf_sym_strtab *symstrtab;
bfd_byte *outbound_syms;
bfd_byte *outbound_shndx;
+ unsigned long outbound_syms_index;
+ unsigned long outbound_shndx_index;
int idx;
unsigned int num_locals;
bfd_size_type amt;
return FALSE;
/* Dump out the symtabs. */
- stt = _bfd_elf_stringtab_init ();
+ stt = _bfd_elf_strtab_init ();
if (stt == NULL)
return FALSE;
symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
symstrtab_hdr->sh_type = SHT_STRTAB;
+ /* Allocate buffer to swap out the .strtab section. */
+ symstrtab = (struct elf_sym_strtab *) bfd_malloc ((symcount + 1)
+ * sizeof (*symstrtab));
+ if (symstrtab == NULL)
+ {
+ _bfd_elf_strtab_free (stt);
+ return FALSE;
+ }
+
outbound_syms = (bfd_byte *) bfd_alloc2 (abfd, 1 + symcount,
bed->s->sizeof_sym);
if (outbound_syms == NULL)
{
- _bfd_stringtab_free (stt);
+error_return:
+ _bfd_elf_strtab_free (stt);
+ free (symstrtab);
return FALSE;
}
symtab_hdr->contents = outbound_syms;
+ outbound_syms_index = 0;
outbound_shndx = NULL;
- symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr;
- if (symtab_shndx_hdr->sh_name != 0)
+ outbound_shndx_index = 0;
+
+ if (elf_symtab_shndx_list (abfd))
{
- amt = (bfd_size_type) (1 + symcount) * sizeof (Elf_External_Sym_Shndx);
- outbound_shndx = (bfd_byte *)
- bfd_zalloc2 (abfd, 1 + symcount, sizeof (Elf_External_Sym_Shndx));
- if (outbound_shndx == NULL)
+ symtab_shndx_hdr = & elf_symtab_shndx_list (abfd)->hdr;
+ if (symtab_shndx_hdr->sh_name != 0)
{
- _bfd_stringtab_free (stt);
- return FALSE;
- }
+ amt = (bfd_size_type) (1 + symcount) * sizeof (Elf_External_Sym_Shndx);
+ outbound_shndx = (bfd_byte *)
+ bfd_zalloc2 (abfd, 1 + symcount, sizeof (Elf_External_Sym_Shndx));
+ if (outbound_shndx == NULL)
+ goto error_return;
- symtab_shndx_hdr->contents = outbound_shndx;
- symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX;
- symtab_shndx_hdr->sh_size = amt;
- symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx);
- symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx);
+ symtab_shndx_hdr->contents = outbound_shndx;
+ symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX;
+ symtab_shndx_hdr->sh_size = amt;
+ symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx);
+ symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx);
+ }
+ /* FIXME: What about any other headers in the list ? */
}
/* Now generate the data (for "contents"). */
sym.st_other = 0;
sym.st_shndx = SHN_UNDEF;
sym.st_target_internal = 0;
- bed->s->swap_symbol_out (abfd, &sym, outbound_syms, outbound_shndx);
- outbound_syms += bed->s->sizeof_sym;
+ symstrtab[0].sym = sym;
+ symstrtab[0].dest_index = outbound_syms_index;
+ symstrtab[0].destshndx_index = outbound_shndx_index;
+ outbound_syms_index++;
if (outbound_shndx != NULL)
- outbound_shndx += sizeof (Elf_External_Sym_Shndx);
+ outbound_shndx_index++;
}
name_local_sections
&& bed->elf_backend_name_local_section_symbols (abfd));
syms = bfd_get_outsymbols (abfd);
- for (idx = 0; idx < symcount; idx++)
+ for (idx = 0; idx < symcount;)
{
Elf_Internal_Sym sym;
bfd_vma value = syms[idx]->value;
&& (flags & (BSF_SECTION_SYM | BSF_GLOBAL)) == BSF_SECTION_SYM)
{
/* Local section symbols have no name. */
- sym.st_name = 0;
+ sym.st_name = (unsigned long) -1;
}
else
{
- sym.st_name = (unsigned long) _bfd_stringtab_add (stt,
- syms[idx]->name,
- TRUE, FALSE);
+ /* Call _bfd_elf_strtab_offset after _bfd_elf_strtab_finalize
+ to get the final offset for st_name. */
+ sym.st_name
+ = (unsigned long) _bfd_elf_strtab_add (stt, syms[idx]->name,
+ FALSE);
if (sym.st_name == (unsigned long) -1)
- {
- _bfd_stringtab_free (stt);
- return FALSE;
- }
+ goto error_return;
}
type_ptr = elf_symbol_from (abfd, syms[idx]);
shndx = elf_shstrtab_sec (abfd);
break;
case MAP_SYM_SHNDX:
- shndx = elf_symtab_shndx (abfd);
+ if (elf_symtab_shndx_list (abfd))
+ shndx = elf_symtab_shndx_list (abfd)->ndx;
break;
default:
shndx = SHN_ABS;
section of a symbol to be a section that is
actually in the output file. */
sec2 = bfd_get_section_by_name (abfd, sec->name);
- if (sec2 == NULL)
+ if (sec2 != NULL)
+ shndx = _bfd_elf_section_from_bfd_section (abfd, sec2);
+ if (shndx == SHN_BAD)
{
+ /* xgettext:c-format */
_bfd_error_handler (_("\
Unable to find equivalent output section for symbol '%s' from section '%s'"),
syms[idx]->name ? syms[idx]->name : "<Local sym>",
sec->name);
bfd_set_error (bfd_error_invalid_operation);
- _bfd_stringtab_free (stt);
- return FALSE;
+ goto error_return;
}
-
- shndx = _bfd_elf_section_from_bfd_section (abfd, sec2);
- BFD_ASSERT (shndx != SHN_BAD);
}
}
}
else if (bfd_is_com_section (syms[idx]->section))
{
-#ifdef USE_STT_COMMON
- if (type == STT_OBJECT)
- sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_COMMON);
- else
-#endif
- sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
+ if (type != STT_TLS)
+ {
+ if ((abfd->flags & BFD_CONVERT_ELF_COMMON))
+ type = ((abfd->flags & BFD_USE_ELF_STT_COMMON)
+ ? STT_COMMON : STT_OBJECT);
+ else
+ type = ((flags & BSF_ELF_COMMON) != 0
+ ? STT_COMMON : STT_OBJECT);
+ }
+ sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
}
else if (bfd_is_und_section (syms[idx]->section))
sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK)
sym.st_target_internal = 0;
}
- bed->s->swap_symbol_out (abfd, &sym, outbound_syms, outbound_shndx);
- outbound_syms += bed->s->sizeof_sym;
+ idx++;
+ symstrtab[idx].sym = sym;
+ symstrtab[idx].dest_index = outbound_syms_index;
+ symstrtab[idx].destshndx_index = outbound_shndx_index;
+
+ outbound_syms_index++;
if (outbound_shndx != NULL)
- outbound_shndx += sizeof (Elf_External_Sym_Shndx);
+ outbound_shndx_index++;
}
+ /* Finalize the .strtab section. */
+ _bfd_elf_strtab_finalize (stt);
+
+ /* Swap out the .strtab section. */
+ for (idx = 0; idx <= symcount; idx++)
+ {
+ struct elf_sym_strtab *elfsym = &symstrtab[idx];
+ if (elfsym->sym.st_name == (unsigned long) -1)
+ elfsym->sym.st_name = 0;
+ else
+ elfsym->sym.st_name = _bfd_elf_strtab_offset (stt,
+ elfsym->sym.st_name);
+ bed->s->swap_symbol_out (abfd, &elfsym->sym,
+ (outbound_syms
+ + (elfsym->dest_index
+ * bed->s->sizeof_sym)),
+ (outbound_shndx
+ + (elfsym->destshndx_index
+ * sizeof (Elf_External_Sym_Shndx))));
+ }
+ free (symstrtab);
+
*sttp = stt;
- symstrtab_hdr->sh_size = _bfd_stringtab_size (stt);
+ symstrtab_hdr->sh_size = _bfd_elf_strtab_size (stt);
symstrtab_hdr->sh_type = SHT_STRTAB;
-
- symstrtab_hdr->sh_flags = 0;
+ symstrtab_hdr->sh_flags = bed->elf_strtab_flags;
symstrtab_hdr->sh_addr = 0;
symstrtab_hdr->sh_entsize = 0;
symstrtab_hdr->sh_link = 0;
if (hdr->sh_info == 0 || hdr->sh_size < sizeof (Elf_External_Verneed))
{
error_return_bad_verref:
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%B: .gnu.version_r invalid entry"), abfd);
bfd_set_error (bfd_error_bad_value);
error_return_verref:
if (hdr->sh_info == 0 || hdr->sh_size < sizeof (Elf_External_Verdef))
{
error_return_bad_verdef:
- (*_bfd_error_handler)
+ _bfd_error_handler
(_("%B: .gnu.version_d invalid entry"), abfd);
bfd_set_error (bfd_error_bad_value);
error_return_verdef:
goto error_return_bad_verdef;
iverdef = &iverdefarr[(iverdefmem.vd_ndx & VERSYM_VERSION) - 1];
- memcpy (iverdef, &iverdefmem, sizeof (Elf_Internal_Verdef));
+ memcpy (iverdef, &iverdefmem, offsetof (Elf_Internal_Verdef, vd_bfd));
iverdef->vd_bfd = abfd;
((bfd_byte *) everdaux + iverdaux->vda_next));
}
+ iverdef->vd_nodename = NULL;
if (iverdef->vd_cnt)
iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename;
if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_')
return TRUE;
- /* Treat assembler generated local labels as local. */
- if (name[0] == 'L' && name[strlen (name) - 1] < 32)
- return TRUE;
+ /* Treat assembler generated fake symbols, dollar local labels and
+ forward-backward labels (aka local labels) as locals.
+ These labels have the form:
+
+ L0^A.* (fake symbols)
+
+ [.]?L[0123456789]+{^A|^B}[0123456789]* (local labels)
+
+ Versions which start with .L will have already been matched above,
+ so we only need to match the rest. */
+ if (name[0] == 'L' && ISDIGIT (name[1]))
+ {
+ bfd_boolean ret = FALSE;
+ const char * p;
+ char c;
+
+ for (p = name + 2; (c = *p); p++)
+ {
+ if (c == 1 || c == 2)
+ {
+ if (c == 1 && p == name + 2)
+ /* A fake symbol. */
+ return TRUE;
+
+ /* FIXME: We are being paranoid here and treating symbols like
+ L0^Bfoo as if there were non-local, on the grounds that the
+ assembler will never generate them. But can any symbol
+ containing an ASCII value in the range 1-31 ever be anything
+ other than some kind of local ? */
+ ret = TRUE;
+ }
+
+ if (! ISDIGIT (c))
+ {
+ ret = FALSE;
+ break;
+ }
+ }
+ return ret;
+ }
return FALSE;
}
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
int ret = bed->s->sizeof_ehdr;
- if (!info->relocatable)
+ if (!bfd_link_relocatable (info))
{
bfd_size_type phdr_size = elf_program_header_size (abfd);
return TRUE;
fail:
- (*_bfd_error_handler)
+ _bfd_error_handler
+ /* xgettext:c-format */
(_("%B: unsupported relocation type %s"),
abfd, areloc->howto->name);
bfd_set_error (bfd_error_bad_value);
if (note->namesz == 6
&& strcmp (note->namedata, "LINUX") == 0)
return elfcore_grok_xstatereg (abfd, note);
- else if (note->namesz == 8
- && strcmp (note->namedata, "FreeBSD") == 0)
- return elfcore_grok_xstatereg (abfd, note);
else
return TRUE;
case NT_SIGINFO:
return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.siginfo",
note);
+
}
}
static bfd_boolean
elfobj_grok_gnu_build_id (bfd *abfd, Elf_Internal_Note *note)
{
- struct elf_obj_tdata *t;
+ struct bfd_build_id* build_id;
if (note->descsz == 0)
return FALSE;
- t = elf_tdata (abfd);
- t->build_id = bfd_alloc (abfd, sizeof (*t->build_id) - 1 + note->descsz);
- if (t->build_id == NULL)
+ build_id = bfd_alloc (abfd, sizeof (struct bfd_build_id) - 1 + note->descsz);
+ if (build_id == NULL)
return FALSE;
- t->build_id->size = note->descsz;
- memcpy (t->build_id->data, note->descdata, note->descsz);
+ build_id->size = note->descsz;
+ memcpy (build_id->data, note->descdata, note->descsz);
+ abfd->build_id = build_id;
return TRUE;
}
}
}
+static bfd_boolean
+elfcore_grok_freebsd_psinfo (bfd *abfd, Elf_Internal_Note *note)
+{
+ size_t offset;
+
+ switch (abfd->arch_info->bits_per_word)
+ {
+ case 32:
+ if (note->descsz < 108)
+ return FALSE;
+ break;
+
+ case 64:
+ if (note->descsz < 120)
+ return FALSE;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ /* Check for version 1 in pr_version. */
+ if (bfd_h_get_32 (abfd, (bfd_byte *) note->descdata) != 1)
+ return FALSE;
+ offset = 4;
+
+ /* Skip over pr_psinfosz. */
+ if (abfd->arch_info->bits_per_word == 32)
+ offset += 4;
+ else
+ {
+ offset += 4; /* Padding before pr_psinfosz. */
+ offset += 8;
+ }
+
+ /* pr_fname is PRFNAMESZ (16) + 1 bytes in size. */
+ elf_tdata (abfd)->core->program
+ = _bfd_elfcore_strndup (abfd, note->descdata + offset, 17);
+ offset += 17;
+
+ /* pr_psargs is PRARGSZ (80) + 1 bytes in size. */
+ elf_tdata (abfd)->core->command
+ = _bfd_elfcore_strndup (abfd, note->descdata + offset, 81);
+ offset += 81;
+
+ /* Padding before pr_pid. */
+ offset += 2;
+
+ /* The pr_pid field was added in version "1a". */
+ if (note->descsz < offset + 4)
+ return TRUE;
+
+ elf_tdata (abfd)->core->pid
+ = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
+
+ return TRUE;
+}
+
+static bfd_boolean
+elfcore_grok_freebsd_prstatus (bfd *abfd, Elf_Internal_Note *note)
+{
+ size_t offset;
+ size_t size;
+
+ /* Check for version 1 in pr_version. */
+ if (bfd_h_get_32 (abfd, (bfd_byte *) note->descdata) != 1)
+ return FALSE;
+ offset = 4;
+
+ /* Skip over pr_statussz. */
+ switch (abfd->arch_info->bits_per_word)
+ {
+ case 32:
+ offset += 4;
+ break;
+
+ case 64:
+ offset += 4; /* Padding before pr_statussz. */
+ offset += 8;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ /* Extract size of pr_reg from pr_gregsetsz. */
+ if (abfd->arch_info->bits_per_word == 32)
+ size = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
+ else
+ size = bfd_h_get_64 (abfd, (bfd_byte *) note->descdata + offset);
+
+ /* Skip over pr_gregsetsz and pr_fpregsetsz. */
+ offset += (abfd->arch_info->bits_per_word / 8) * 2;
+
+ /* Skip over pr_osreldate. */
+ offset += 4;
+
+ /* Read signal from pr_cursig. */
+ if (elf_tdata (abfd)->core->signal == 0)
+ elf_tdata (abfd)->core->signal
+ = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
+ offset += 4;
+
+ /* Read TID from pr_pid. */
+ elf_tdata (abfd)->core->lwpid
+ = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
+ offset += 4;
+
+ /* Padding before pr_reg. */
+ if (abfd->arch_info->bits_per_word == 64)
+ offset += 4;
+
+ /* Make a ".reg/999" section and a ".reg" section. */
+ return _bfd_elfcore_make_pseudosection (abfd, ".reg",
+ size, note->descpos + offset);
+}
+
+static bfd_boolean
+elfcore_grok_freebsd_note (bfd *abfd, Elf_Internal_Note *note)
+{
+ switch (note->type)
+ {
+ case NT_PRSTATUS:
+ return elfcore_grok_freebsd_prstatus (abfd, note);
+
+ case NT_FPREGSET:
+ return elfcore_grok_prfpreg (abfd, note);
+
+ case NT_PRPSINFO:
+ return elfcore_grok_freebsd_psinfo (abfd, note);
+
+ case NT_FREEBSD_THRMISC:
+ if (note->namesz == 8)
+ return elfcore_make_note_pseudosection (abfd, ".thrmisc", note);
+ else
+ return TRUE;
+
+ case NT_FREEBSD_PROCSTAT_AUXV:
+ {
+ asection *sect = bfd_make_section_anyway_with_flags (abfd, ".auxv",
+ SEC_HAS_CONTENTS);
+
+ if (sect == NULL)
+ return FALSE;
+ sect->size = note->descsz - 4;
+ sect->filepos = note->descpos + 4;
+ sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32;
+
+ return TRUE;
+ }
+
+ case NT_X86_XSTATE:
+ if (note->namesz == 8)
+ return elfcore_grok_xstatereg (abfd, note);
+ else
+ return TRUE;
+
+ default:
+ return TRUE;
+ }
+}
+
static bfd_boolean
elfcore_netbsd_get_lwpid (Elf_Internal_Note *note, int *lwpidp)
{
{
struct elf_external_linux_prpsinfo32 data;
- memset (&data, 0, sizeof (data));
- LINUX_PRPSINFO32_SWAP_FIELDS (abfd, prpsinfo, data);
-
+ swap_linux_prpsinfo32_out (abfd, prpsinfo, &data);
return elfcore_write_note (abfd, buf, bufsiz, "CORE", NT_PRPSINFO,
&data, sizeof (data));
}
{
struct elf_external_linux_prpsinfo64 data;
- memset (&data, 0, sizeof (data));
- LINUX_PRPSINFO64_SWAP_FIELDS (abfd, prpsinfo, data);
-
+ swap_linux_prpsinfo64_out (abfd, prpsinfo, &data);
return elfcore_write_note (abfd, buf, bufsiz,
"CORE", NT_PRPSINFO, &data, sizeof (data));
}
grokers[] =
{
GROKER_ELEMENT ("", elfcore_grok_note),
+ GROKER_ELEMENT ("FreeBSD", elfcore_grok_freebsd_note),
GROKER_ELEMENT ("NetBSD-CORE", elfcore_grok_netbsd_note),
GROKER_ELEMENT ( "OpenBSD", elfcore_grok_openbsd_note),
GROKER_ELEMENT ("QNX", elfcore_grok_nto_note),
sym->st_value + addend);
}
+/* Adjust an address within a section. Given OFFSET within SEC, return
+ the new offset within the section, based upon changes made to the
+ section. Returns -1 if the offset is now invalid.
+ The offset (in abnd out) is in target sized bytes, however big a
+ byte may be. */
+
bfd_vma
_bfd_elf_section_offset (bfd *abfd,
struct bfd_link_info *info,
offset);
case SEC_INFO_TYPE_EH_FRAME:
return _bfd_elf_eh_frame_section_offset (abfd, info, sec, offset);
+
default:
if ((sec->flags & SEC_ELF_REVERSE_COPY) != 0)
{
+ /* Reverse the offset. */
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
bfd_size_type address_size = bed->s->arch_size / 8;
- offset = sec->size - offset - address_size;
+
+ /* address_size and sec->size are in octets. Convert
+ to bytes before subtracting the original offset. */
+ offset = (sec->size - address_size) / bfd_octets_per_byte (abfd) - offset;
}
return offset;
}
return n;
}
-/* It is only used by x86-64 so far. */
+/* It is only used by x86-64 so far.
+ ??? This repeats *COM* id of zero. sec->id is supposed to be unique,
+ but current usage would allow all of _bfd_std_section to be zero. t*/
asection _bfd_elf_large_com_section
- = BFD_FAKE_SECTION (_bfd_elf_large_com_section,
- SEC_IS_COMMON, NULL, "LARGE_COMMON", 0);
+ = BFD_FAKE_SECTION (_bfd_elf_large_com_section, NULL,
+ "LARGE_COMMON", 0, SEC_IS_COMMON);
void
_bfd_elf_post_process_headers (bfd * abfd,