/* ELF executable support for BFD.
- Copyright (C) 1993-2019 Free Software Foundation, Inc.
+ Copyright (C) 1993-2020 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
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 elf_strtab_hash **, int) ;
-static bfd_boolean elf_read_notes (bfd *, file_ptr, bfd_size_type,
- size_t align) ;
static bfd_boolean elf_parse_notes (bfd *abfd, char *buf, size_t size,
file_ptr offset, size_t align);
return elf_tdata (abfd)->core != NULL;
}
-static char *
+char *
bfd_elf_get_str_section (bfd *abfd, unsigned int shindex)
{
Elf_Internal_Shdr **i_shdrp;
/* Allocate and clear an extra byte at the end, to prevent crashes
in case the string table is not terminated. */
if (shstrtabsize + 1 <= 1
- || shstrtabsize > bfd_get_file_size (abfd)
|| bfd_seek (abfd, offset, SEEK_SET) != 0
- || (shstrtab = (bfd_byte *) bfd_alloc (abfd, shstrtabsize + 1)) == NULL)
- shstrtab = NULL;
- else if (bfd_bread (shstrtab, shstrtabsize, abfd) != shstrtabsize)
+ || (shstrtab = _bfd_alloc_and_read (abfd, shstrtabsize + 1,
+ shstrtabsize)) == NULL)
{
- if (bfd_get_error () != bfd_error_system_call)
- bfd_set_error (bfd_error_file_truncated);
- bfd_release (abfd, shstrtab);
- shstrtab = NULL;
/* Once we've failed to read it, make sure we don't keep
trying. Otherwise, we'll keep allocating space for
the string table over and over. */
Elf_Internal_Sym *isymend;
const struct elf_backend_data *bed;
size_t extsym_size;
- bfd_size_type amt;
+ size_t amt;
file_ptr pos;
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
alloc_intsym = NULL;
bed = get_elf_backend_data (ibfd);
extsym_size = bed->s->sizeof_sym;
- amt = (bfd_size_type) symcount * extsym_size;
+ if (_bfd_mul_overflow (symcount, extsym_size, &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ intsym_buf = NULL;
+ goto out;
+ }
pos = symtab_hdr->sh_offset + symoffset * extsym_size;
if (extsym_buf == NULL)
{
- alloc_ext = bfd_malloc2 (symcount, extsym_size);
+ alloc_ext = bfd_malloc (amt);
extsym_buf = alloc_ext;
}
if (extsym_buf == NULL
extshndx_buf = NULL;
else
{
- amt = (bfd_size_type) symcount * sizeof (Elf_External_Sym_Shndx);
+ if (_bfd_mul_overflow (symcount, sizeof (Elf_External_Sym_Shndx), &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ intsym_buf = NULL;
+ goto out;
+ }
pos = shndx_hdr->sh_offset + symoffset * sizeof (Elf_External_Sym_Shndx);
if (extshndx_buf == NULL)
{
- alloc_extshndx = (Elf_External_Sym_Shndx *)
- bfd_malloc2 (symcount, sizeof (Elf_External_Sym_Shndx));
+ alloc_extshndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt);
extshndx_buf = alloc_extshndx;
}
if (extshndx_buf == NULL
if (intsym_buf == NULL)
{
- alloc_intsym = (Elf_Internal_Sym *)
- bfd_malloc2 (symcount, sizeof (Elf_Internal_Sym));
+ if (_bfd_mul_overflow (symcount, sizeof (Elf_Internal_Sym), &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ goto out;
+ }
+ alloc_intsym = (Elf_Internal_Sym *) bfd_malloc (amt);
intsym_buf = alloc_intsym;
if (intsym_buf == NULL)
goto out;
_bfd_error_handler (_("%pB symbol number %lu references"
" nonexistent SHT_SYMTAB_SHNDX section"),
ibfd, (unsigned long) symoffset);
- if (alloc_intsym != NULL)
- free (alloc_intsym);
+ free (alloc_intsym);
intsym_buf = NULL;
goto out;
}
out:
- if (alloc_ext != NULL)
- free (alloc_ext);
- if (alloc_extshndx != NULL)
- free (alloc_extshndx);
+ free (alloc_ext);
+ free (alloc_extshndx);
return intsym_buf;
}
{
/* We keep a list of elf section headers for group sections,
so we can find them quickly. */
- bfd_size_type amt;
+ size_t amt;
elf_tdata (abfd)->num_group = num_group;
- elf_tdata (abfd)->group_sect_ptr = (Elf_Internal_Shdr **)
- bfd_alloc2 (abfd, num_group, sizeof (Elf_Internal_Shdr *));
+ amt = num_group * sizeof (Elf_Internal_Shdr *);
+ elf_tdata (abfd)->group_sect_ptr
+ = (Elf_Internal_Shdr **) bfd_zalloc (abfd, amt);
if (elf_tdata (abfd)->group_sect_ptr == NULL)
return FALSE;
- memset (elf_tdata (abfd)->group_sect_ptr, 0,
- num_group * sizeof (Elf_Internal_Shdr *));
num_group = 0;
for (i = 0; i < shnum; i++)
num_group += 1;
/* Read the raw contents. */
- BFD_ASSERT (sizeof (*dest) >= 4);
- amt = shdr->sh_size * sizeof (*dest) / 4;
- shdr->contents = (unsigned char *)
- bfd_alloc2 (abfd, shdr->sh_size, sizeof (*dest) / 4);
- /* PR binutils/4110: Handle corrupt group headers. */
- if (shdr->contents == NULL)
- {
- _bfd_error_handler
- /* xgettext:c-format */
- (_("%pB: corrupt size field in group section"
- " header: %#" PRIx64),
- abfd, (uint64_t) shdr->sh_size);
- bfd_set_error (bfd_error_bad_value);
- -- num_group;
- continue;
- }
-
- 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))
+ BFD_ASSERT (sizeof (*dest) >= 4 && sizeof (*dest) % 4 == 0);
+ shdr->contents = NULL;
+ if (_bfd_mul_overflow (shdr->sh_size,
+ sizeof (*dest) / 4, &amt)
+ || bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0
+ || !(shdr->contents
+ = _bfd_alloc_and_read (abfd, amt, shdr->sh_size)))
{
_bfd_error_handler
/* xgettext:c-format */
abfd, (uint64_t) shdr->sh_size);
bfd_set_error (bfd_error_bad_value);
-- num_group;
- /* PR 17510: If the group contents are even
- partially corrupt, do not allow any of the
- contents to be used. */
- memset (shdr->contents, 0, amt);
continue;
}
idx = H_GET_32 (abfd, src);
if (src == shdr->contents)
{
+ dest->shdr = NULL;
dest->flags = idx;
if (shdr->bfd_section != NULL && (idx & GRP_COMDAT))
shdr->bfd_section->flags
if (elfsec == 0)
{
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 */
- (_("%pB: warning: sh_link not set for section `%pA'"),
- abfd, s);
+ bed->link_order_error_handler
+ /* xgettext:c-format */
+ (_("%pB: warning: sh_link not set for section `%pA'"),
+ abfd, s);
}
else
{
asection *newsect;
flagword flags;
const struct elf_backend_data *bed;
+ unsigned int opb = bfd_octets_per_byte (abfd, NULL);
if (hdr->bfd_section != NULL)
return TRUE;
newsect->filepos = hdr->sh_offset;
- if (!bfd_set_section_vma (newsect, hdr->sh_addr)
- || !bfd_set_section_size (newsect, hdr->sh_size)
- || !bfd_set_section_alignment (newsect, bfd_log2 (hdr->sh_addralign)))
- return FALSE;
-
flags = SEC_NO_FLAGS;
if (hdr->sh_type != SHT_NOBITS)
flags |= SEC_HAS_CONTENTS;
not any sort of flag. Their SEC_ALLOC bits are cleared. */
if (name [0] == '.')
{
- const char *p;
- int n;
- if (name[1] == 'd')
- p = ".debug", n = 6;
- else if (name[1] == 'g' && name[2] == 'n')
- p = ".gnu.linkonce.wi.", n = 17;
- else if (name[1] == 'g' && name[2] == 'd')
- p = ".gdb_index", n = 11; /* yes we really do mean 11. */
- else if (name[1] == 'l')
- p = ".line", n = 5;
- else if (name[1] == 's')
- p = ".stab", n = 5;
- else if (name[1] == 'z')
- p = ".zdebug", n = 7;
- else
- p = NULL, n = 0;
- if (p != NULL && strncmp (name, p, n) == 0)
+ if (strncmp (name, ".debug", 6) == 0
+ || strncmp (name, ".gnu.linkonce.wi.", 17) == 0
+ || strncmp (name, ".zdebug", 7) == 0)
+ flags |= SEC_DEBUGGING | SEC_ELF_OCTETS;
+ else if (strncmp (name, GNU_BUILD_ATTRS_SECTION_NAME, 21) == 0
+ || strncmp (name, ".note.gnu", 9) == 0)
+ {
+ flags |= SEC_ELF_OCTETS;
+ opb = 1;
+ }
+ else if (strncmp (name, ".line", 5) == 0
+ || strncmp (name, ".stab", 5) == 0
+ || strcmp (name, ".gdb_index") == 0)
flags |= SEC_DEBUGGING;
}
}
+ if (!bfd_set_section_vma (newsect, hdr->sh_addr / opb)
+ || !bfd_set_section_size (newsect, hdr->sh_size)
+ || !bfd_set_section_alignment (newsect, bfd_log2 (hdr->sh_addralign)))
+ return FALSE;
+
/* As a GNU extension, if the name begins with .gnu.linkonce, we
only link a single copy of the section. This is used to support
g++. g++ will emit each template expansion in its own section.
&& elf_next_in_group (newsect) == NULL)
flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
+ if (!bfd_set_section_flags (newsect, flags))
+ return FALSE;
+
bed = get_elf_backend_data (abfd);
if (bed->elf_backend_section_flags)
- if (! bed->elf_backend_section_flags (&flags, hdr))
+ if (!bed->elf_backend_section_flags (hdr))
return FALSE;
- if (!bfd_set_section_flags (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. */
free (contents);
}
- if ((flags & SEC_ALLOC) != 0)
+ if ((newsect->flags & SEC_ALLOC) != 0)
{
Elf_Internal_Phdr *phdr;
unsigned int i, nload;
|| phdr->p_type == PT_TLS)
&& ELF_SECTION_IN_SEGMENT (hdr, phdr))
{
- if ((flags & SEC_LOAD) == 0)
+ if ((newsect->flags & SEC_LOAD) == 0)
newsect->lma = (phdr->p_paddr
- + hdr->sh_addr - phdr->p_vaddr);
+ + hdr->sh_addr - phdr->p_vaddr) / opb;
else
/* We used to use the same adjustment for SEC_LOAD
sections, but that doesn't work if the segment
segment will contain sections with contiguous
LMAs, even if the VMAs are not. */
newsect->lma = (phdr->p_paddr
- + hdr->sh_offset - phdr->p_offset);
+ + hdr->sh_offset - phdr->p_offset) / opb;
/* With contiguous segments, we can't tell from file
offsets whether a section with zero size should
/* Compress/decompress DWARF debug sections with names: .debug_* and
.zdebug_*, after the section flags is set. */
- if ((flags & SEC_DEBUGGING)
+ if ((newsect->flags & SEC_DEBUGGING)
&& ((name[1] == 'd' && name[6] == '_')
|| (name[1] == 'z' && name[7] == '_')))
{
}
/* 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))
+ if (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
{
/* 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);
+ (void) bed->elf_backend_copy_special_section_fields (ibfd, obfd,
+ NULL, oheader);
}
}
return TRUE;
error_return:
- if (dynbuf != NULL)
- free (dynbuf);
+ free (dynbuf);
return FALSE;
}
-/* Get version string. */
+/* Get version name. If BASE_P is TRUE, return "Base" for VER_FLG_BASE
+ and return symbol version for symbol version itself. */
const char *
_bfd_elf_get_symbol_version_string (bfd *abfd, asymbol *symbol,
+ bfd_boolean base_p,
bfd_boolean *hidden)
{
const char *version_string = NULL;
&& (vernum > elf_tdata (abfd)->cverdefs
|| (elf_tdata (abfd)->verdef[0].vd_flags
== VER_FLG_BASE)))
- version_string = "Base";
+ version_string = base_p ? "Base" : "";
else if (vernum <= elf_tdata (abfd)->cverdefs)
- version_string =
- elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
+ {
+ const char *nodename
+ = elf_tdata (abfd)->verdef[vernum - 1].vd_nodename;
+ version_string = "";
+ if (base_p
+ || nodename == NULL
+ || symbol->name == NULL
+ || strcmp (symbol->name, nodename) != 0)
+ version_string = nodename;
+ }
else
{
Elf_Internal_Verneed *t;
/* If we have version information, print it. */
version_string = _bfd_elf_get_symbol_version_string (abfd,
symbol,
+ TRUE,
&hidden);
if (version_string)
{
sections_being_created = NULL;
if (sections_being_created == NULL)
{
- sections_being_created = (bfd_boolean *)
- bfd_zalloc2 (abfd, elf_numsections (abfd), sizeof (bfd_boolean));
+ size_t amt = elf_numsections (abfd) * sizeof (bfd_boolean);
+
+ /* PR 26005: Do not use bfd_zalloc here as the memory might
+ be released before the bfd has been fully scanned. */
+ sections_being_created = (bfd_boolean *) bfd_malloc (amt);
+ if (sections_being_created == NULL)
+ return FALSE;
+ memset (sections_being_created, FALSE, amt);
sections_being_created_abfd = abfd;
}
if (sections_being_created [shindex])
sections. */
if (*p_hdr != NULL)
{
- _bfd_error_handler
- /* xgettext:c-format */
- (_("%pB: warning: multiple relocation sections for section %pA \
-found - ignoring all but the first"),
- abfd, target_sect);
+ if (!bed->init_secondary_reloc_section (abfd, hdr, name, shindex))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB: warning: secondary relocation section '%s' "
+ "for section %pA found - ignoring"),
+ abfd, name, target_sect);
+ }
goto success;
}
+
hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, sizeof (*hdr2));
if (hdr2 == NULL)
goto fail;
sections_being_created [shindex] = FALSE;
if (-- nesting == 0)
{
+ free (sections_being_created);
sections_being_created = NULL;
- sections_being_created_abfd = abfd;
+ sections_being_created_abfd = NULL;
}
return ret;
}
static const struct bfd_elf_special_section special_sections_c[] =
{
{ STRING_COMMA_LEN (".comment"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".ctf"), 0, SHT_PROGBITS, 0 },
{ NULL, 0, 0, 0, 0 }
};
bed = get_elf_backend_data (abfd);
sec->use_rela_p = bed->default_use_rela_p;
- /* When we read a file, we don't need to set ELF section type and
- flags. They will be overridden in _bfd_elf_make_section_from_shdr
- anyway. We will set ELF section type and flags for all linker
- created sections. If user specifies BFD section flags, we will
- set ELF section type and flags based on BFD section flags in
- elf_fake_sections. Special handling for .init_array/.fini_array
- output sections since they may contain .ctors/.dtors input
- sections. We don't want _bfd_elf_init_private_section_data to
- copy ELF section type from .ctors/.dtors input sections. */
- if (abfd->direction != read_direction
- || (sec->flags & SEC_LINKER_CREATED) != 0)
+ /* Set up ELF section type and flags for newly created sections, if
+ there is an ABI mandated section. */
+ ssect = (*bed->get_sec_type_attr) (abfd, sec);
+ if (ssect != NULL)
{
- ssect = (*bed->get_sec_type_attr) (abfd, sec);
- if (ssect != NULL
- && (!sec->flags
- || (sec->flags & SEC_LINKER_CREATED) != 0
- || ssect->type == SHT_INIT_ARRAY
- || ssect->type == SHT_FINI_ARRAY))
- {
- elf_section_type (sec) = ssect->type;
- elf_section_flags (sec) = ssect->attr;
- }
+ elf_section_type (sec) = ssect->type;
+ elf_section_flags (sec) = ssect->attr;
}
return _bfd_generic_new_section_hook (abfd, sec);
char namebuf[64];
size_t len;
int split;
+ unsigned int opb = bfd_octets_per_byte (abfd, NULL);
split = ((hdr->p_memsz > 0)
&& (hdr->p_filesz > 0)
newsect = bfd_make_section (abfd, name);
if (newsect == NULL)
return FALSE;
- newsect->vma = hdr->p_vaddr;
- newsect->lma = hdr->p_paddr;
+ newsect->vma = hdr->p_vaddr / opb;
+ newsect->lma = hdr->p_paddr / opb;
newsect->size = hdr->p_filesz;
newsect->filepos = hdr->p_offset;
newsect->flags |= SEC_HAS_CONTENTS;
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->vma = (hdr->p_vaddr + hdr->p_filesz) / opb;
+ newsect->lma = (hdr->p_paddr + hdr->p_filesz) / opb;
newsect->size = hdr->p_memsz - hdr->p_filesz;
newsect->filepos = hdr->p_offset + hdr->p_filesz;
align = newsect->vma & -newsect->vma;
return TRUE;
}
+static bfd_boolean
+_bfd_elf_core_find_build_id (bfd *templ, bfd_vma offset)
+{
+ /* The return value is ignored. Build-ids are considered optional. */
+ if (templ->xvec->flavour == bfd_target_elf_flavour)
+ return (*get_elf_backend_data (templ)->elf_backend_core_find_build_id)
+ (templ, offset);
+ return FALSE;
+}
+
bfd_boolean
bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int hdr_index)
{
return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "null");
case PT_LOAD:
- return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "load");
+ if (! _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "load"))
+ return FALSE;
+ if (bfd_get_format (abfd) == bfd_core && abfd->build_id == NULL)
+ _bfd_elf_core_find_build_id (abfd, hdr->p_offset);
+ return TRUE;
case PT_DYNAMIC:
return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "dynamic");
unsigned int sh_type;
const char *name = asect->name;
bfd_boolean delay_st_name_p = FALSE;
+ bfd_vma mask;
if (arg->failed)
{
/* Set SEC_ELF_COMPRESS to indicate this section should be
compressed. */
asect->flags |= SEC_ELF_COMPRESS;
-
/* 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. */
if ((asect->flags & SEC_ALLOC) != 0
|| asect->user_set_vma)
- this_hdr->sh_addr = asect->vma;
+ this_hdr->sh_addr = asect->vma * bfd_octets_per_byte (abfd, asect);
else
this_hdr->sh_addr = 0;
arg->failed = TRUE;
return;
}
- this_hdr->sh_addralign = (bfd_vma) 1 << asect->alignment_power;
+ /* Set sh_addralign to the highest power of two given by alignment
+ consistent with the section VMA. Linker scripts can force VMA. */
+ mask = ((bfd_vma) 1 << asect->alignment_power) | this_hdr->sh_addr;
+ this_hdr->sh_addralign = mask & -mask;
/* The sh_entsize and sh_info fields may have been set already by
copy_private_section_data. */
if (symindx == 0)
{
/* If called from the assembler, swap_out_syms will have set up
- elf_section_syms. */
- BFD_ASSERT (elf_section_syms (abfd) != NULL);
+ elf_section_syms.
+ PR 25699: A corrupt input file could contain bogus group info. */
+ if (elf_section_syms (abfd) == NULL)
+ {
+ *failedptr = TRUE;
+ return;
+ }
symindx = elf_section_syms (abfd)[sec->index]->udata.i;
}
elf_section_data (sec)->this_hdr.sh_info = symindx;
Elf_Internal_Shdr **i_shdrp;
struct bfd_elf_section_data *d;
bfd_boolean need_symtab;
+ size_t amt;
section_number = 1;
/* Set up the list of section header pointers, in agreement with the
indices. */
- i_shdrp = (Elf_Internal_Shdr **) bfd_zalloc2 (abfd, section_number,
- sizeof (Elf_Internal_Shdr *));
+ amt = section_number * sizeof (Elf_Internal_Shdr *);
+ i_shdrp = (Elf_Internal_Shdr **) bfd_zalloc (abfd, amt);
if (i_shdrp == NULL)
return FALSE;
where s is NULL. */
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 */
- (_("%pB: warning: sh_link not set for section `%pA'"),
- abfd, sec);
+ bed->link_order_error_handler
+ /* xgettext:c-format */
+ (_("%pB: warning: sh_link not set for section `%pA'"),
+ abfd, sec);
}
}
elf_section_data (s)->this_hdr.sh_link = d->this_idx;
/* This is a .stab section. */
- if (elf_section_data (s)->this_hdr.sh_entsize == 0)
- elf_section_data (s)->this_hdr.sh_entsize
- = 4 + 2 * bfd_get_arch_size (abfd) / 8;
+ elf_section_data (s)->this_hdr.sh_entsize = 12;
}
}
break;
unsigned int idx;
asection *asect;
asymbol **new_syms;
+ size_t amt;
#ifdef DEBUG
fprintf (stderr, "elf_map_symbols\n");
}
max_index++;
- sect_syms = (asymbol **) bfd_zalloc2 (abfd, max_index, sizeof (asymbol *));
+ amt = max_index * sizeof (asymbol *);
+ sect_syms = (asymbol **) bfd_zalloc (abfd, amt);
if (sect_syms == NULL)
return FALSE;
elf_section_syms (abfd) = sect_syms;
}
/* Now sort the symbols so the local symbols are first. */
- new_syms = (asymbol **) bfd_alloc2 (abfd, num_locals + num_globals,
- sizeof (asymbol *));
-
+ amt = (num_locals + num_globals) * sizeof (asymbol *);
+ new_syms = (asymbol **) bfd_alloc (abfd, amt);
if (new_syms == NULL)
return FALSE;
if (bed->elf_backend_begin_write_processing)
(*bed->elf_backend_begin_write_processing) (abfd, link_info);
- if (! prep_headers (abfd))
+ if (!(*bed->elf_backend_init_file_header) (abfd, link_info))
return FALSE;
- /* Post process the headers if necessary. */
- (*bed->elf_backend_post_process_headers) (abfd, link_info);
-
fsargs.failed = FALSE;
fsargs.link_info = link_info;
bfd_map_over_sections (abfd, elf_fake_sections, &fsargs);
}
shstrtab_hdr = &elf_tdata (abfd)->shstrtab_hdr;
- /* sh_name was set in prep_headers. */
+ /* sh_name was set in init_file_header. */
shstrtab_hdr->sh_type = SHT_STRTAB;
shstrtab_hdr->sh_flags = bed->elf_strtab_flags;
shstrtab_hdr->sh_addr = 0;
struct elf_segment_map *m;
unsigned int i;
asection **hdrpp;
- bfd_size_type amt;
+ size_t amt;
amt = sizeof (struct elf_segment_map) - sizeof (asection *);
amt += (to - from) * sizeof (asection *);
bfd_boolean phdr_in_segment;
bfd_boolean writable;
bfd_boolean executable;
- int tls_count = 0;
+ unsigned int tls_count = 0;
asection *first_tls = NULL;
asection *first_mbind = NULL;
asection *dynsec, *eh_frame_hdr;
- bfd_size_type amt;
- bfd_vma addr_mask, wrap_to = 0;
- bfd_size_type phdr_size;
+ size_t amt;
+ bfd_vma addr_mask, wrap_to = 0; /* Bytes. */
+ bfd_size_type phdr_size; /* Octets/bytes. */
+ unsigned int opb = bfd_octets_per_byte (abfd, NULL);
/* Select the allocated sections, and sort them. */
- sections = (asection **) bfd_malloc2 (bfd_count_sections (abfd),
- sizeof (asection *));
+ amt = bfd_count_sections (abfd) * sizeof (asection *);
+ sections = (asection **) bfd_malloc (amt);
if (sections == NULL)
goto error_return;
{
if ((s->flags & SEC_ALLOC) != 0)
{
+ /* target_index is unused until bfd_elf_final_link
+ starts output of section symbols. Use it to make
+ qsort stable. */
+ s->target_index = i;
sections[i] = s;
++i;
/* A wrapping section potentially clashes with header. */
- if (((s->lma + s->size) & addr_mask) < (s->lma & addr_mask))
- wrap_to = (s->lma + s->size) & addr_mask;
+ if (((s->lma + s->size / opb) & addr_mask) < (s->lma & addr_mask))
+ wrap_to = (s->lma + s->size / opb) & addr_mask;
}
}
BFD_ASSERT (i <= bfd_count_sections (abfd));
if (phdr_size == (bfd_size_type) -1)
phdr_size = get_program_header_size (abfd, info);
phdr_size += bed->s->sizeof_ehdr;
+ /* phdr_size is compared to LMA values which are in bytes. */
+ phdr_size /= opb;
maxpagesize = bed->maxpagesize;
if (maxpagesize == 0)
maxpagesize = 1;
program headers we will need. */
if (phdr_in_segment && count > 0)
{
- bfd_vma phdr_lma;
+ bfd_vma phdr_lma; /* Bytes. */
bfd_boolean separate_phdr = FALSE;
phdr_lma = (sections[0]->lma - phdr_size) & addr_mask & -maxpagesize;
m = make_mapping (abfd, sections, 0, 0, phdr_in_segment);
if (m == NULL)
goto error_return;
- m->p_paddr = phdr_lma;
+ m->p_paddr = phdr_lma * opb;
m->p_vaddr_offset
= (sections[0]->vma - phdr_size) & addr_mask & -maxpagesize;
m->p_paddr_valid = 1;
executable = TRUE;
last_hdr = hdr;
/* .tbss sections effectively have zero size. */
- last_size = !IS_TBSS (hdr) ? hdr->size : 0;
+ last_size = (!IS_TBSS (hdr) ? hdr->size : 0) / opb;
continue;
}
last_hdr = hdr;
/* .tbss sections effectively have zero size. */
- last_size = !IS_TBSS (hdr) ? hdr->size : 0;
+ last_size = (!IS_TBSS (hdr) ? hdr->size : 0) / opb;
hdr_index = i;
phdr_in_segment = FALSE;
}
if (s2->next->alignment_power == alignment_power
&& (s2->next->flags & SEC_LOAD) != 0
&& elf_section_type (s2->next) == SHT_NOTE
- && align_power (s2->lma + s2->size,
+ && align_power (s2->lma + s2->size / opb,
alignment_power)
== s2->next->lma)
count++;
m->p_flags = PF_R;
m->p_flags_valid = 1;
s = first_tls;
- for (i = 0; i < (unsigned int) tls_count; ++i)
+ for (i = 0; i < tls_count; ++i)
{
if ((s->flags & SEC_THREAD_LOCAL) == 0)
{
(_("%pB: TLS sections are not adjacent:"), abfd);
s = first_tls;
i = 0;
- while (i < (unsigned int) tls_count)
+ while (i < tls_count)
{
if ((s->flags & SEC_THREAD_LOCAL) != 0)
{
{
i = m->count;
while (--i != (unsigned) -1)
- if ((m->sections[i]->flags & (SEC_LOAD | SEC_HAS_CONTENTS))
- == (SEC_LOAD | SEC_HAS_CONTENTS))
- break;
+ {
+ if (m->sections[i]->size > 0
+ && (m->sections[i]->flags & (SEC_LOAD | SEC_HAS_CONTENTS))
+ == (SEC_LOAD | SEC_HAS_CONTENTS))
+ break;
+ }
if (i != (unsigned) -1)
break;
return TRUE;
error_return:
- if (sections != NULL)
- free (sections);
+ free (sections);
return FALSE;
}
if (TOEND (sec1))
{
- if (TOEND (sec2))
- {
- /* If the indices are the same, do not return 0
- here, but continue to try the next comparison. */
- if (sec1->target_index - sec2->target_index != 0)
- return sec1->target_index - sec2->target_index;
- }
- else
+ if (!TOEND (sec2))
return 1;
}
else if (TOEND (sec2))
return sec1->target_index - sec2->target_index;
}
+/* This qsort comparison functions sorts PT_LOAD segments first and
+ by p_paddr, for assign_file_positions_for_load_sections. */
+
+static int
+elf_sort_segments (const void *arg1, const void *arg2)
+{
+ const struct elf_segment_map *m1 = *(const struct elf_segment_map **) arg1;
+ const struct elf_segment_map *m2 = *(const struct elf_segment_map **) arg2;
+
+ if (m1->p_type != m2->p_type)
+ {
+ if (m1->p_type == PT_NULL)
+ return 1;
+ if (m2->p_type == PT_NULL)
+ return -1;
+ return m1->p_type < m2->p_type ? -1 : 1;
+ }
+ if (m1->includes_filehdr != m2->includes_filehdr)
+ return m1->includes_filehdr ? -1 : 1;
+ if (m1->no_sort_lma != m2->no_sort_lma)
+ return m1->no_sort_lma ? -1 : 1;
+ if (m1->p_type == PT_LOAD && !m1->no_sort_lma)
+ {
+ bfd_vma lma1, lma2; /* Octets. */
+ lma1 = 0;
+ if (m1->p_paddr_valid)
+ lma1 = m1->p_paddr;
+ else if (m1->count != 0)
+ {
+ unsigned int opb = bfd_octets_per_byte (m1->sections[0]->owner,
+ m1->sections[0]);
+ lma1 = (m1->sections[0]->lma + m1->p_vaddr_offset) * opb;
+ }
+ lma2 = 0;
+ if (m2->p_paddr_valid)
+ lma2 = m2->p_paddr;
+ else if (m2->count != 0)
+ {
+ unsigned int opb = bfd_octets_per_byte (m2->sections[0]->owner,
+ m2->sections[0]);
+ lma2 = (m2->sections[0]->lma + m2->p_vaddr_offset) * opb;
+ }
+ if (lma1 != lma2)
+ return lma1 < lma2 ? -1 : 1;
+ }
+ if (m1->idx != m2->idx)
+ return m1->idx < m2->idx ? -1 : 1;
+ return 0;
+}
+
/* Ian Lance Taylor writes:
We shouldn't be using % with a negative signed number. That's just
{
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
struct elf_segment_map *m;
+ struct elf_segment_map *phdr_load_seg;
Elf_Internal_Phdr *phdrs;
Elf_Internal_Phdr *p;
- file_ptr off;
+ file_ptr off; /* Octets. */
bfd_size_type maxpagesize;
- unsigned int pt_load_count = 0;
- unsigned int alloc;
+ unsigned int alloc, actual;
unsigned int i, j;
- bfd_vma header_pad = 0;
+ struct elf_segment_map **sorted_seg_map;
+ unsigned int opb = bfd_octets_per_byte (abfd, NULL);
if (link_info == NULL
&& !_bfd_elf_map_sections_to_segments (abfd, link_info))
alloc = 0;
for (m = elf_seg_map (abfd); m != NULL; m = m->next)
- {
- ++alloc;
- if (m->header_size)
- header_pad = m->header_size;
- }
+ m->idx = alloc++;
if (alloc)
{
elf_elfheader (abfd)->e_phnum = alloc;
if (elf_program_header_size (abfd) == (bfd_size_type) -1)
- elf_program_header_size (abfd) = alloc * bed->s->sizeof_phdr;
+ {
+ actual = alloc;
+ elf_program_header_size (abfd) = alloc * bed->s->sizeof_phdr;
+ }
else
- BFD_ASSERT (elf_program_header_size (abfd)
- >= alloc * bed->s->sizeof_phdr);
+ {
+ actual = elf_program_header_size (abfd) / bed->s->sizeof_phdr;
+ BFD_ASSERT (elf_program_header_size (abfd)
+ == actual * bed->s->sizeof_phdr);
+ BFD_ASSERT (actual >= alloc);
+ }
if (alloc == 0)
{
See ld/emultempl/elf-generic.em:gld${EMULATION_NAME}_map_segments
where the layout is forced to according to a larger size in the
last iterations for the testcase ld-elf/header. */
- BFD_ASSERT (elf_program_header_size (abfd) % bed->s->sizeof_phdr
- == 0);
- phdrs = (Elf_Internal_Phdr *)
- bfd_zalloc2 (abfd,
- (elf_program_header_size (abfd) / bed->s->sizeof_phdr),
- sizeof (Elf_Internal_Phdr));
+ phdrs = bfd_zalloc (abfd, (actual * sizeof (*phdrs)
+ + alloc * sizeof (*sorted_seg_map)));
+ sorted_seg_map = (struct elf_segment_map **) (phdrs + actual);
elf_tdata (abfd)->phdr = phdrs;
if (phdrs == NULL)
return FALSE;
- maxpagesize = 1;
- if ((abfd->flags & D_PAGED) != 0)
- maxpagesize = bed->maxpagesize;
-
- off = bed->s->sizeof_ehdr;
- off += alloc * bed->s->sizeof_phdr;
- if (header_pad < (bfd_vma) off)
- header_pad = 0;
- else
- header_pad -= off;
- off += header_pad;
-
- for (m = elf_seg_map (abfd), p = phdrs, j = 0;
- m != NULL;
- m = m->next, p++, j++)
+ for (m = elf_seg_map (abfd), j = 0; m != NULL; m = m->next, j++)
{
- asection **secpp;
- bfd_vma off_adjust;
- bfd_boolean no_contents;
-
+ sorted_seg_map[j] = m;
/* If elf_segment_map is not from map_sections_to_segments, the
sections may not be correctly ordered. NOTE: sorting should
not be done to the PT_NOTE section of a corefile, which may
if (m->count > 1
&& !(elf_elfheader (abfd)->e_type == ET_CORE
&& m->p_type == PT_NOTE))
- qsort (m->sections, (size_t) m->count, sizeof (asection *),
- elf_sort_sections);
+ {
+ for (i = 0; i < m->count; i++)
+ m->sections[i]->target_index = i;
+ qsort (m->sections, (size_t) m->count, sizeof (asection *),
+ elf_sort_sections);
+ }
+ }
+ if (alloc > 1)
+ qsort (sorted_seg_map, alloc, sizeof (*sorted_seg_map),
+ elf_sort_segments);
+
+ maxpagesize = 1;
+ if ((abfd->flags & D_PAGED) != 0)
+ maxpagesize = bed->maxpagesize;
+
+ /* Sections must map to file offsets past the ELF file header. */
+ off = bed->s->sizeof_ehdr;
+ /* And if one of the PT_LOAD headers doesn't include the program
+ headers then we'll be mapping program headers in the usual
+ position after the ELF file header. */
+ phdr_load_seg = NULL;
+ for (j = 0; j < alloc; j++)
+ {
+ m = sorted_seg_map[j];
+ if (m->p_type != PT_LOAD)
+ break;
+ if (m->includes_phdrs)
+ {
+ phdr_load_seg = m;
+ break;
+ }
+ }
+ if (phdr_load_seg == NULL)
+ off += actual * bed->s->sizeof_phdr;
+
+ for (j = 0; j < alloc; j++)
+ {
+ asection **secpp;
+ bfd_vma off_adjust; /* Octets. */
+ bfd_boolean no_contents;
/* An ELF segment (described by Elf_Internal_Phdr) may contain a
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. */
+ m = sorted_seg_map[j];
+ p = phdrs + m->idx;
p->p_type = m->p_type;
p->p_flags = m->p_flags;
if (m->count == 0)
- p->p_vaddr = m->p_vaddr_offset;
+ p->p_vaddr = m->p_vaddr_offset * opb;
else
- p->p_vaddr = m->sections[0]->vma + m->p_vaddr_offset;
+ p->p_vaddr = (m->sections[0]->vma + m->p_vaddr_offset) * opb;
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 + m->p_vaddr_offset;
+ p->p_paddr = (m->sections[0]->lma + m->p_vaddr_offset) * opb;
if (p->p_type == PT_LOAD
&& (abfd->flags & D_PAGED) != 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;
else if (m->count == 0)
p->p_align = 1 << bed->s->log_file_align;
- else
- p->p_align = 0;
+
+ if (m == phdr_load_seg)
+ {
+ if (!m->includes_filehdr)
+ p->p_offset = off;
+ off += actual * bed->s->sizeof_phdr;
+ }
no_contents = FALSE;
off_adjust = 0;
if (p->p_type == PT_LOAD
&& m->count > 0)
{
- bfd_size_type align;
+ bfd_size_type align; /* Bytes. */
unsigned int align_power = 0;
if (m->p_align_valid)
break;
}
- off_adjust = vma_page_aligned_bias (p->p_vaddr, off, align);
+ off_adjust = vma_page_aligned_bias (p->p_vaddr, off, align * opb);
/* 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
+ if (j != 0
+ && (abfd->flags & D_PAGED) != 0
&& bed->no_page_alias
&& (off & (maxpagesize - 1)) != 0
- && (off & -maxpagesize) == ((off + off_adjust) & -maxpagesize))
+ && ((off & -maxpagesize)
+ == ((off + off_adjust) & -maxpagesize)))
off_adjust += maxpagesize;
off += off_adjust;
if (no_contents)
for (i = 0; i < m->count; i++)
elf_section_type (m->sections[i]) = SHT_NOTE;
- p->p_offset = 0;
- p->p_filesz = 0;
- p->p_memsz = 0;
-
if (m->includes_filehdr)
{
if (!m->p_flags_valid)
p->p_flags |= PF_R;
p->p_filesz = bed->s->sizeof_ehdr;
p->p_memsz = bed->s->sizeof_ehdr;
- if (m->count > 0)
+ if (p->p_type == PT_LOAD)
{
- if (p->p_vaddr < (bfd_vma) off
- || (!m->p_paddr_valid
- && p->p_paddr < (bfd_vma) off))
+ if (m->count > 0)
{
- _bfd_error_handler
- (_("%pB: not enough room for program headers,"
- " try linking with -N"),
- abfd);
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ if (p->p_vaddr < (bfd_vma) off
+ || (!m->p_paddr_valid
+ && p->p_paddr < (bfd_vma) off))
+ {
+ _bfd_error_handler
+ (_("%pB: not enough room for program headers,"
+ " try linking with -N"),
+ abfd);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ p->p_vaddr -= off;
+ if (!m->p_paddr_valid)
+ p->p_paddr -= off;
}
-
- p->p_vaddr -= off;
+ }
+ else if (sorted_seg_map[0]->includes_filehdr)
+ {
+ Elf_Internal_Phdr *filehdr = phdrs + sorted_seg_map[0]->idx;
+ p->p_vaddr = filehdr->p_vaddr;
if (!m->p_paddr_valid)
- p->p_paddr -= off;
+ p->p_paddr = filehdr->p_paddr;
}
}
{
if (!m->p_flags_valid)
p->p_flags |= PF_R;
-
+ p->p_filesz += actual * bed->s->sizeof_phdr;
+ p->p_memsz += actual * bed->s->sizeof_phdr;
if (!m->includes_filehdr)
{
- p->p_offset = bed->s->sizeof_ehdr;
-
- if (m->count > 0)
+ if (p->p_type == PT_LOAD)
+ {
+ elf_elfheader (abfd)->e_phoff = p->p_offset;
+ if (m->count > 0)
+ {
+ p->p_vaddr -= off - p->p_offset;
+ if (!m->p_paddr_valid)
+ p->p_paddr -= off - p->p_offset;
+ }
+ }
+ else if (phdr_load_seg != NULL)
{
- p->p_vaddr -= off - p->p_offset;
+ Elf_Internal_Phdr *phdr = phdrs + phdr_load_seg->idx;
+ bfd_vma phdr_off = 0; /* Octets. */
+ if (phdr_load_seg->includes_filehdr)
+ phdr_off = bed->s->sizeof_ehdr;
+ p->p_vaddr = phdr->p_vaddr + phdr_off;
if (!m->p_paddr_valid)
- p->p_paddr -= off - p->p_offset;
+ p->p_paddr = phdr->p_paddr + phdr_off;
+ p->p_offset = phdr->p_offset + phdr_off;
}
- }
-
- p->p_filesz += alloc * bed->s->sizeof_phdr;
- p->p_memsz += alloc * bed->s->sizeof_phdr;
- if (m->count)
- {
- p->p_filesz += header_pad;
- p->p_memsz += header_pad;
+ else
+ p->p_offset = bed->s->sizeof_ehdr;
}
}
|| (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core))
{
if (!m->includes_filehdr && !m->includes_phdrs)
- p->p_offset = off;
+ {
+ p->p_offset = off;
+ if (no_contents)
+ {
+ /* Put meaningless p_offset for PT_LOAD segments
+ without file contents somewhere within the first
+ page, in an attempt to not point past EOF. */
+ bfd_size_type align = maxpagesize;
+ if (align < p->p_align)
+ align = p->p_align;
+ if (align < 1)
+ align = 1;
+ p->p_offset = off % align;
+ }
+ }
else
{
- file_ptr adjust;
+ file_ptr adjust; /* Octets. */
adjust = off - (p->p_offset + p->p_filesz);
if (!no_contents)
&& ((this_hdr->sh_flags & SHF_TLS) == 0
|| p->p_type == PT_TLS))))
{
- bfd_vma p_start = p->p_paddr;
- bfd_vma p_end = p_start + p->p_memsz;
- bfd_vma s_start = sec->lma;
- bfd_vma adjust = s_start - p_end;
+ bfd_vma p_start = p->p_paddr; /* Octets. */
+ bfd_vma p_end = p_start + p->p_memsz; /* Octets. */
+ bfd_vma s_start = sec->lma * opb; /* Octets. */
+ bfd_vma adjust = s_start - p_end; /* Octets. */
if (adjust != 0
&& (s_start < p_end
_bfd_error_handler
/* xgettext:c-format */
(_("%pB: section %pA lma %#" PRIx64 " adjusted to %#" PRIx64),
- abfd, sec, (uint64_t) s_start, (uint64_t) p_end);
+ abfd, sec, (uint64_t) s_start / opb,
+ (uint64_t) p_end / opb);
adjust = 0;
- sec->lma = p_end;
+ sec->lma = p_end / opb;
}
p->p_memsz += adjust;
- if (this_hdr->sh_type != SHT_NOBITS)
+ if (p->p_type == PT_LOAD)
{
- if (p->p_filesz + adjust < p->p_memsz)
+ if (this_hdr->sh_type != SHT_NOBITS)
{
- /* We have a PROGBITS section following NOBITS ones.
- Allocate file space for the NOBITS section(s) and
- zero it. */
- adjust = p->p_memsz - p->p_filesz;
- if (!write_zeros (abfd, off, adjust))
- return FALSE;
+ off_adjust = 0;
+ if (p->p_filesz + adjust < p->p_memsz)
+ {
+ /* We have a PROGBITS section following NOBITS ones.
+ Allocate file space for the NOBITS section(s) and
+ zero it. */
+ adjust = p->p_memsz - p->p_filesz;
+ if (!write_zeros (abfd, off, adjust))
+ return FALSE;
+ }
+ }
+ /* We only adjust sh_offset in SHT_NOBITS sections
+ as would seem proper for their address when the
+ section is first in the segment. sh_offset
+ doesn't really have any significance for
+ SHT_NOBITS anyway, apart from a notional position
+ relative to other sections. Historically we
+ didn't bother with adjusting sh_offset and some
+ programs depend on it not being adjusted. See
+ pr12921 and pr25662. */
+ if (this_hdr->sh_type != SHT_NOBITS || i == 0)
+ {
+ off += adjust;
+ if (this_hdr->sh_type == SHT_NOBITS)
+ off_adjust += adjust;
}
- off += adjust;
- p->p_filesz += adjust;
}
+ if (this_hdr->sh_type != SHT_NOBITS)
+ p->p_filesz += adjust;
}
if (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core)
off -= off_adjust;
+ /* PR ld/20815 - Check that the program header segment, if
+ present, will be loaded into memory. */
+ if (p->p_type == PT_PHDR
+ && phdr_load_seg == NULL
+ && !(bed->elf_backend_allow_non_load_phdr != NULL
+ && bed->elf_backend_allow_non_load_phdr (abfd, phdrs, alloc)))
+ {
+ /* 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 (_("%pB: error: PHDR segment not covered"
+ " by LOAD segment"),
+ abfd);
+ if (link_info == NULL)
+ return FALSE;
+ /* Arrange for the linker to exit with an error, deleting
+ the output file unless --noinhibit-exec is given. */
+ link_info->callbacks->info ("%X");
+ }
+
/* 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)
}
elf_next_file_pos (abfd) = off;
+
+ if (link_info != NULL
+ && phdr_load_seg != NULL
+ && phdr_load_seg->includes_filehdr)
+ {
+ /* There is a segment that contains both the file headers and the
+ program headers, so provide a symbol __ehdr_start pointing there.
+ A program can use this to examine itself robustly. */
+
+ struct elf_link_hash_entry *hash
+ = elf_link_hash_lookup (elf_hash_table (link_info), "__ehdr_start",
+ FALSE, FALSE, TRUE);
+ /* If the symbol was referenced and not defined, define it. */
+ if (hash != NULL
+ && (hash->root.type == bfd_link_hash_new
+ || hash->root.type == bfd_link_hash_undefined
+ || hash->root.type == bfd_link_hash_undefweak
+ || hash->root.type == bfd_link_hash_common))
+ {
+ asection *s = NULL;
+ bfd_vma filehdr_vaddr = phdrs[phdr_load_seg->idx].p_vaddr / opb;
+
+ if (phdr_load_seg->count != 0)
+ /* The segment contains sections, so use the first one. */
+ s = phdr_load_seg->sections[0];
+ else
+ /* Use the first (i.e. lowest-addressed) section in any segment. */
+ for (m = elf_seg_map (abfd); m != NULL; m = m->next)
+ if (m->p_type == PT_LOAD && m->count != 0)
+ {
+ s = m->sections[0];
+ break;
+ }
+
+ if (s != NULL)
+ {
+ hash->root.u.def.value = filehdr_vaddr - s->vma;
+ hash->root.u.def.section = s;
+ }
+ else
+ {
+ hash->root.u.def.value = filehdr_vaddr;
+ hash->root.u.def.section = bfd_abs_section_ptr;
+ }
+
+ hash->root.type = bfd_link_hash_defined;
+ hash->def_regular = 1;
+ hash->non_elf = 0;
+ }
+ }
+
return TRUE;
}
return TRUE;
}
-/* Assign file positions for the other sections. */
+/* Assign file positions for the other sections, except for compressed debugging
+ and other sections assigned in _bfd_elf_assign_file_positions_for_non_load(). */
static bfd_boolean
assign_file_positions_for_non_load_sections (bfd *abfd,
Elf_Internal_Phdr *phdrs;
Elf_Internal_Phdr *p;
struct elf_segment_map *m;
- struct elf_segment_map *hdrs_segment;
- bfd_vma filehdr_vaddr, filehdr_paddr;
- bfd_vma phdrs_vaddr, phdrs_paddr;
file_ptr off;
- unsigned int count;
+ unsigned int opb = bfd_octets_per_byte (abfd, NULL);
i_shdrpp = elf_elfsections (abfd);
end_hdrpp = i_shdrpp + elf_numsections (abfd);
}
else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
&& hdr->bfd_section == NULL)
+ /* We don't know the offset of these sections yet: their size has
+ not been decided. */
|| (hdr->bfd_section != NULL
- && (hdr->bfd_section->flags & SEC_ELF_COMPRESS))
- /* Compress DWARF debug sections. */
+ && (hdr->bfd_section->flags & SEC_ELF_COMPRESS
+ || (bfd_section_is_ctf (hdr->bfd_section)
+ && abfd->is_linker_output)))
|| hdr == i_shdrpp[elf_onesymtab (abfd)]
|| (elf_symtab_shndx_list (abfd) != NULL
&& hdr == i_shdrpp[elf_symtab_shndx_list (abfd)->ndx])
else
off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE);
}
+ elf_next_file_pos (abfd) = off;
/* Now that we have set the section file positions, we can set up
the file positions for the non PT_LOAD segments. */
- count = 0;
- filehdr_vaddr = 0;
- filehdr_paddr = 0;
- phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr;
- phdrs_paddr = 0;
- hdrs_segment = NULL;
phdrs = elf_tdata (abfd)->phdr;
for (m = elf_seg_map (abfd), p = phdrs; m != NULL; m = m->next, p++)
{
- ++count;
- if (p->p_type != PT_LOAD)
- continue;
-
- if (m->includes_filehdr)
- {
- filehdr_vaddr = p->p_vaddr;
- filehdr_paddr = p->p_paddr;
- }
- if (m->includes_phdrs)
+ if (p->p_type == PT_GNU_RELRO)
{
- phdrs_vaddr = p->p_vaddr;
- phdrs_paddr = p->p_paddr;
- if (m->includes_filehdr)
+ bfd_vma start, end; /* Bytes. */
+ bfd_boolean ok;
+
+ if (link_info != NULL)
{
- hdrs_segment = m;
- phdrs_vaddr += bed->s->sizeof_ehdr;
- phdrs_paddr += bed->s->sizeof_ehdr;
- }
- }
- }
-
- if (hdrs_segment != NULL && link_info != NULL)
- {
- /* There is a segment that contains both the file headers and the
- program headers, so provide a symbol __ehdr_start pointing there.
- A program can use this to examine itself robustly. */
-
- struct elf_link_hash_entry *hash
- = elf_link_hash_lookup (elf_hash_table (link_info), "__ehdr_start",
- FALSE, FALSE, TRUE);
- /* If the symbol was referenced and not defined, define it. */
- if (hash != NULL
- && (hash->root.type == bfd_link_hash_new
- || hash->root.type == bfd_link_hash_undefined
- || hash->root.type == bfd_link_hash_undefweak
- || hash->root.type == bfd_link_hash_common))
- {
- asection *s = NULL;
- if (hdrs_segment->count != 0)
- /* The segment contains sections, so use the first one. */
- s = hdrs_segment->sections[0];
- else
- /* Use the first (i.e. lowest-addressed) section in any segment. */
- for (m = elf_seg_map (abfd); m != NULL; m = m->next)
- if (m->count != 0)
- {
- s = m->sections[0];
- break;
- }
-
- if (s != NULL)
- {
- hash->root.u.def.value = filehdr_vaddr - s->vma;
- hash->root.u.def.section = s;
- }
- else
- {
- hash->root.u.def.value = filehdr_vaddr;
- hash->root.u.def.section = bfd_abs_section_ptr;
- }
-
- hash->root.type = bfd_link_hash_defined;
- hash->def_regular = 1;
- hash->non_elf = 0;
- }
- }
-
- for (m = elf_seg_map (abfd), p = phdrs; m != NULL; m = m->next, p++)
- {
- if (p->p_type == PT_GNU_RELRO)
- {
- bfd_vma start, end;
- bfd_boolean ok;
-
- if (link_info != NULL)
- {
- /* During linking the range of the RELRO segment is passed
- in link_info. Note that there may be padding between
- relro_start and the first RELRO section. */
- start = link_info->relro_start;
- end = link_info->relro_end;
+ /* During linking the range of the RELRO segment is passed
+ in link_info. Note that there may be padding between
+ relro_start and the first RELRO section. */
+ start = link_info->relro_start;
+ end = link_info->relro_end;
}
else if (m->count != 0)
{
if (!m->p_size_valid)
abort ();
start = m->sections[0]->vma;
- end = start + m->p_size;
+ end = start + m->p_size / opb;
}
else
{
&& lm->count != 0
&& (lm->sections[lm->count - 1]->vma
+ (!IS_TBSS (lm->sections[lm->count - 1])
- ? lm->sections[lm->count - 1]->size
+ ? lm->sections[lm->count - 1]->size / opb
: 0)) > start
&& lm->sections[0]->vma < end)
break;
if (i < lm->count)
{
- p->p_vaddr = lm->sections[i]->vma;
- p->p_paddr = lm->sections[i]->lma;
+ p->p_vaddr = lm->sections[i]->vma * opb;
+ p->p_paddr = lm->sections[i]->lma * opb;
p->p_offset = lm->sections[i]->filepos;
- p->p_memsz = end - p->p_vaddr;
+ p->p_memsz = end * opb - p->p_vaddr;
p->p_filesz = p->p_memsz;
/* The RELRO segment typically ends a few bytes
}
}
}
- else if (m->includes_filehdr)
- {
- p->p_vaddr = filehdr_vaddr;
- if (! m->p_paddr_valid)
- p->p_paddr = filehdr_paddr;
- }
- else if (m->includes_phdrs)
- {
- p->p_vaddr = phdrs_vaddr;
- if (! m->p_paddr_valid)
- p->p_paddr = phdrs_paddr;
- }
}
- elf_next_file_pos (abfd) = off;
-
return TRUE;
}
VMAs must be known before this is called.
Reloc sections come in two flavours: Those processed specially as
- "side-channel" data attached to a section to which they apply, and
- those that bfd doesn't process as relocations. The latter sort are
- stored in a normal bfd section by bfd_section_from_shdr. We don't
- consider the former sort here, unless they form part of the loadable
- image. Reloc sections not assigned here will be handled later by
+ "side-channel" data attached to a section to which they apply, and those that
+ bfd doesn't process as relocations. The latter sort are stored in a normal
+ bfd section by bfd_section_from_shdr. We don't consider the former sort
+ here, unless they form part of the loadable image. Reloc sections not
+ assigned here (and compressed debugging sections and CTF sections which
+ nothing else in the file can rely upon) will be handled later by
assign_file_positions_for_relocs.
We also don't set the positions of the .symtab and .strtab here. */
struct elf_obj_tdata *tdata = elf_tdata (abfd);
Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd);
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ unsigned int alloc;
if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0
&& bfd_get_format (abfd) != bfd_core)
hdr = *hdrpp;
if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA)
&& hdr->bfd_section == NULL)
+ /* Do not assign offsets for these sections yet: we don't know
+ their sizes. */
|| (hdr->bfd_section != NULL
- && (hdr->bfd_section->flags & SEC_ELF_COMPRESS))
- /* Compress DWARF debug sections. */
+ && (hdr->bfd_section->flags & SEC_ELF_COMPRESS
+ || (bfd_section_is_ctf (hdr->bfd_section)
+ && abfd->is_linker_output)))
|| i == elf_onesymtab (abfd)
|| (elf_symtab_shndx_list (abfd) != NULL
&& hdr == i_shdrpp[elf_symtab_shndx_list (abfd)->ndx])
}
elf_next_file_pos (abfd) = off;
+ elf_program_header_size (abfd) = 0;
}
else
{
- unsigned int alloc;
-
/* Assign file positions for the loaded sections based on the
assignment of sections to segments. */
if (!assign_file_positions_for_load_sections (abfd, link_info))
/* And for non-load sections. */
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;
- }
-
- /* Set e_type in ELF header to ET_EXEC for -pie -Ttext-segment=. */
- 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;
- Elf_Internal_Phdr *end_segment = &segment[num_segments];
-
- /* Find the lowest p_vaddr in PT_LOAD segments. */
- bfd_vma p_vaddr = (bfd_vma) -1;
- for (; segment < end_segment; segment++)
- if (segment->p_type == PT_LOAD && p_vaddr > segment->p_vaddr)
- p_vaddr = segment->p_vaddr;
-
- /* Set e_type to ET_EXEC if the lowest p_vaddr in PT_LOAD
- segments is non-zero. */
- if (p_vaddr)
- i_ehdrp->e_type = ET_EXEC;
- }
-
- /* Write out the program headers. */
- alloc = elf_elfheader (abfd)->e_phnum;
- 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 == NULL
- || !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 (_("%pB: error: PHDR segment not covered"
- " by LOAD segment"),
- abfd);
- return FALSE;
- }
+ if (!(*bed->elf_backend_modify_headers) (abfd, link_info))
+ return FALSE;
- if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0
+ /* Write out the program headers. */
+ alloc = i_ehdrp->e_phnum;
+ if (alloc != 0)
+ {
+ if (bfd_seek (abfd, i_ehdrp->e_phoff, SEEK_SET) != 0
|| bed->s->write_out_phdrs (abfd, tdata->phdr, alloc) != 0)
return FALSE;
}
return TRUE;
}
-static bfd_boolean
-prep_headers (bfd *abfd)
+bfd_boolean
+_bfd_elf_init_file_header (bfd *abfd,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form. */
struct elf_strtab_hash *shstrtab;
i_ehdrp->e_entry = bfd_get_start_address (abfd);
i_ehdrp->e_shentsize = bed->s->sizeof_shdr;
- /* If we're building an executable, we'll need a program header table. */
- if (abfd->flags & EXEC_P)
- /* It all happens later. */
- ;
- else
- {
- i_ehdrp->e_phentsize = 0;
- i_ehdrp->e_phoff = 0;
- }
-
elf_tdata (abfd)->symtab_hdr.sh_name =
(unsigned int) _bfd_elf_strtab_add (shstrtab, ".symtab", FALSE);
elf_tdata (abfd)->strtab_hdr.sh_name =
return TRUE;
}
+/* Set e_type in ELF header to ET_EXEC for -pie -Ttext-segment=.
+
+ 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. */
+
+bfd_boolean
+_bfd_elf_modify_headers (bfd *obfd, struct bfd_link_info *link_info)
+{
+ if (link_info != NULL && bfd_link_pie (link_info))
+ {
+ Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (obfd);
+ unsigned int num_segments = i_ehdrp->e_phnum;
+ struct elf_obj_tdata *tdata = elf_tdata (obfd);
+ Elf_Internal_Phdr *segment = tdata->phdr;
+ Elf_Internal_Phdr *end_segment = &segment[num_segments];
+
+ /* Find the lowest p_vaddr in PT_LOAD segments. */
+ bfd_vma p_vaddr = (bfd_vma) -1;
+ for (; segment < end_segment; segment++)
+ if (segment->p_type == PT_LOAD && p_vaddr > segment->p_vaddr)
+ p_vaddr = segment->p_vaddr;
+
+ /* Set e_type to ET_EXEC if the lowest p_vaddr in PT_LOAD
+ segments is non-zero. */
+ if (p_vaddr)
+ i_ehdrp->e_type = ET_EXEC;
+ }
+ return TRUE;
+}
+
/* Assign file positions for all the reloc sections which are not part
of the loadable file image, and the file position of section headers. */
asection *sec = shdrp->bfd_section;
bfd_boolean is_rel = (shdrp->sh_type == SHT_REL
|| shdrp->sh_type == SHT_RELA);
+ bfd_boolean is_ctf = sec && bfd_section_is_ctf (sec);
if (is_rel
+ || is_ctf
|| (sec != NULL && (sec->flags & SEC_ELF_COMPRESS)))
{
- if (!is_rel)
+ if (!is_rel && !is_ctf)
{
const char *name = sec->name;
struct bfd_elf_section_data *d;
shdrp->contents = sec->contents;
shdrp->bfd_section->contents = NULL;
}
+ else if (is_ctf)
+ {
+ /* Update section size and contents. */
+ shdrp->sh_size = sec->size;
+ shdrp->contents = sec->contents;
+ }
+
off = _bfd_elf_assign_file_position_for_section (shdrp,
off,
TRUE);
struct elf_segment_map *phdr_adjust_seg = NULL;
unsigned int phdr_adjust_num = 0;
const struct elf_backend_data *bed;
+ unsigned int opb = bfd_octets_per_byte (ibfd, NULL);
bed = get_elf_backend_data (ibfd);
iehdr = elf_elfheader (ibfd);
/* Returns TRUE if the given section is contained within
the given segment. VMA addresses are compared. */
-#define IS_CONTAINED_BY_VMA(section, segment) \
- (section->vma >= segment->p_vaddr \
- && (section->vma + SECTION_SIZE (section, segment) \
+#define IS_CONTAINED_BY_VMA(section, segment, opb) \
+ (section->vma * (opb) >= segment->p_vaddr \
+ && (section->vma * (opb) + SECTION_SIZE (section, segment) \
<= (SEGMENT_END (segment, segment->p_vaddr))))
/* Returns TRUE if the given section is contained within
the given segment. LMA addresses are compared. */
-#define IS_CONTAINED_BY_LMA(section, segment, base) \
- (section->lma >= base \
- && (section->lma + SECTION_SIZE (section, segment) >= section->lma) \
- && (section->lma + SECTION_SIZE (section, segment) \
+#define IS_CONTAINED_BY_LMA(section, segment, base, opb) \
+ (section->lma * (opb) >= base \
+ && (section->lma + SECTION_SIZE (section, segment) / (opb) >= section->lma) \
+ && (section->lma * (opb) + SECTION_SIZE (section, segment) \
<= SEGMENT_END (segment, base)))
/* Handle PT_NOTE segment. */
7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments.
8. PT_DYNAMIC should not contain empty sections at the beginning
(with the possible exception of .dynamic). */
-#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed) \
+#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed, opb) \
((((segment->p_paddr \
- ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr) \
- : IS_CONTAINED_BY_VMA (section, segment)) \
+ ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr, opb) \
+ : IS_CONTAINED_BY_VMA (section, segment, opb)) \
&& (section->flags & SEC_ALLOC) != 0) \
|| IS_NOTE (segment, section)) \
&& segment->p_type != PT_GNU_STACK \
&& (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 * (opb) \
+ : segment->p_vaddr != section->vma * (opb)) \
|| (strcmp (bfd_section_name (section), ".dynamic") == 0)) \
&& (segment->p_type != PT_LOAD || !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) \
+#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed, opb) \
+ (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed, opb) \
&& section->output_section != NULL)
/* Returns TRUE iff seg1 starts after the end of seg2. */
{
/* Mininal change so that the normal section to segment
assignment code will work. */
- segment->p_vaddr = section->vma;
+ segment->p_vaddr = section->vma * opb;
break;
}
asection *matching_lma;
asection *suggested_lma;
unsigned int j;
- bfd_size_type amt;
+ size_t amt;
asection *first_section;
if (segment->p_type == PT_NULL)
{
/* 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 (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed, opb))
{
if (first_section == NULL)
first_section = section;
/* Allocate a segment map big enough to contain
all of the sections we have selected. */
amt = sizeof (struct elf_segment_map) - sizeof (asection *);
- amt += (bfd_size_type) section_count * sizeof (asection *);
+ amt += section_count * sizeof (asection *);
map = (struct elf_segment_map *) bfd_zalloc (obfd, amt);
if (map == NULL)
return FALSE;
" at vaddr=%#" PRIx64 ", is this intentional?"),
ibfd, (uint64_t) segment->p_vaddr);
- map->p_vaddr_offset = segment->p_vaddr;
+ map->p_vaddr_offset = segment->p_vaddr / opb;
map->count = 0;
*pointer_to_map = map;
pointer_to_map = &map->next;
pointers that we are interested in. As these sections get assigned
to a segment, they are removed from this array. */
- sections = (asection **) bfd_malloc2 (section_count, sizeof (asection *));
+ amt = section_count * sizeof (asection *);
+ sections = (asection **) bfd_malloc (amt);
if (sections == NULL)
return FALSE;
section != NULL;
section = section->next)
{
- if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed))
+ if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed, opb))
{
output_section = section->output_section;
+ (map->includes_phdrs
? iehdr->e_phnum * iehdr->e_phentsize
: 0),
- output_section->alignment_power)
- == output_section->vma))
+ output_section->alignment_power * opb)
+ == (output_section->vma * opb)))
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)
+ if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr,
+ opb)
|| IS_COREFILE_NOTE (segment, section)
|| (bed->want_p_paddr_set_to_zero
- && IS_CONTAINED_BY_VMA (output_section, segment)))
+ && IS_CONTAINED_BY_VMA (output_section, segment, opb)))
{
if (matching_lma == NULL
|| output_section->lma < matching_lma->lma)
pointer_to_map = &map->next;
if (p_paddr_valid
- && !bed->want_p_paddr_set_to_zero
- && matching_lma->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 = map->p_paddr - matching_lma->lma;
+ && !bed->want_p_paddr_set_to_zero)
+ {
+ bfd_vma hdr_size = 0;
+ if (map->includes_filehdr)
+ hdr_size = iehdr->e_ehsize;
+ if (map->includes_phdrs)
+ hdr_size += iehdr->e_phnum * iehdr->e_phentsize;
+
+ /* Account for padding before the first section in the
+ segment. */
+ map->p_vaddr_offset = ((map->p_paddr + hdr_size) / opb
+ - matching_lma->lma);
+ }
free (sections);
continue;
if (matching_lma == NULL)
matching_lma = suggested_lma;
- map->p_paddr = matching_lma->lma;
+ map->p_paddr = matching_lma->lma * opb;
/* Offset the segment physical address from the lma
to allow for space taken up by elf headers. */
the same alignment. */
if (segment->p_align != 0 && segment->p_align < align)
align = segment->p_align;
- map->p_paddr &= -align;
+ map->p_paddr &= -(align * opb);
}
}
BFD_ASSERT (output_section != NULL);
- if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr)
+ if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr,
+ opb)
|| IS_COREFILE_NOTE (segment, section))
{
if (map->count == 0)
+ (map->includes_phdrs
? iehdr->e_phnum * iehdr->e_phentsize
: 0),
- output_section->alignment_power)
- != output_section->lma)
- abort ();
+ output_section->alignment_power * opb)
+ != output_section->lma * opb)
+ goto sorry;
}
else
{
/* PR 23932. A corrupt input file may contain sections that cannot
be assigned to any segment - because for example they have a
- negative size - or segments that do not contain any sections. */
- if (map->count == 0)
- {
- bfd_set_error (bfd_error_bad_value);
- free (sections);
- return FALSE;
- }
+ negative size - or segments that do not contain any sections.
+ But there are also valid reasons why a segment can be empty.
+ So allow a count of zero. */
/* Add the current segment to the list of built segments. */
*pointer_to_map = map;
segments. Create a new segment here, initialise it
and carry on looping. */
amt = sizeof (struct elf_segment_map) - sizeof (asection *);
- amt += (bfd_size_type) section_count * sizeof (asection *);
+ amt += section_count * sizeof (asection *);
map = (struct elf_segment_map *) bfd_zalloc (obfd, amt);
if (map == NULL)
{
map->p_type = segment->p_type;
map->p_flags = segment->p_flags;
map->p_flags_valid = 1;
- map->p_paddr = suggested_lma->lma;
+ map->p_paddr = suggested_lma->lma * opb;
map->p_paddr_valid = p_paddr_valid;
map->includes_filehdr = 0;
map->includes_phdrs = 0;
}
+
+ continue;
+ sorry:
+ bfd_set_error (bfd_error_sorry);
+ free (sections);
+ return FALSE;
}
while (isec < section_count);
unsigned int num_segments;
bfd_boolean phdr_included = FALSE;
bfd_boolean p_paddr_valid;
+ unsigned int opb = bfd_octets_per_byte (ibfd, NULL);
iehdr = elf_elfheader (ibfd);
{
asection *section;
unsigned int section_count;
- bfd_size_type amt;
+ size_t amt;
Elf_Internal_Shdr *this_hdr;
asection *first_section = NULL;
asection *lowest_section;
- bfd_boolean no_contents = TRUE;
/* Compute how many sections are in this segment. */
for (section = ibfd->sections, section_count = 0;
{
if (first_section == NULL)
first_section = section;
- if (elf_section_type (section) != SHT_NOBITS)
- no_contents = FALSE;
section_count++;
}
}
/* Allocate a segment map big enough to contain
all of the sections we have selected. */
amt = sizeof (struct elf_segment_map) - sizeof (asection *);
- amt += (bfd_size_type) section_count * sizeof (asection *);
+ amt += section_count * sizeof (asection *);
map = (struct elf_segment_map *) bfd_zalloc (obfd, amt);
if (map == NULL)
return FALSE;
seg_off = this_hdr->sh_offset - segment->p_offset;
else
seg_off = this_hdr->sh_addr - segment->p_vaddr;
- if (section->lma - segment->p_paddr != seg_off)
+ if (section->lma * opb - segment->p_paddr != seg_off)
map->p_paddr_valid = FALSE;
}
if (isec == section_count)
}
}
- if (map->includes_filehdr && lowest_section != NULL)
+ if (section_count == 0)
+ map->p_vaddr_offset = segment->p_vaddr / opb;
+ else if (map->p_paddr_valid)
{
- /* Try to keep the space used by the headers plus any
- padding fixed. If there are sections with file contents
- in this segment then the lowest sh_offset is the best
- guess. Otherwise the segment only has file contents for
- the headers, and p_filesz is the best guess. */
- if (no_contents)
- map->header_size = segment->p_filesz;
- else
- map->header_size = lowest_section->filepos;
- }
+ /* Account for padding before the first section in the segment. */
+ bfd_vma hdr_size = 0;
+ if (map->includes_filehdr)
+ hdr_size = iehdr->e_ehsize;
+ if (map->includes_phdrs)
+ hdr_size += iehdr->e_phnum * iehdr->e_phentsize;
- if (section_count == 0)
- map->p_vaddr_offset = segment->p_vaddr;
- else if (!map->includes_phdrs
- && !map->includes_filehdr
- && map->p_paddr_valid)
- /* Account for padding before the first section. */
- map->p_vaddr_offset = (segment->p_paddr
- - (lowest_section ? lowest_section->lma : 0));
+ map->p_vaddr_offset = ((map->p_paddr + hdr_size) / opb
+ - (lowest_section ? lowest_section->lma : 0));
+ }
map->count = section_count;
*pointer_to_map = map;
return copy_elf_program_header (ibfd, obfd);
}
-rewrite:
+ rewrite:
if (ibfd->xvec == obfd->xvec)
{
/* When rewriting program header, set the output maxpagesize to
BFD_ASSERT (elf_section_data (osec) != NULL);
- /* For objcopy and relocatable link, don't copy the output ELF
- section type from input if the output BFD section flags have been
- set to something different. For a final link allow some flags
- that the linker clears to differ. */
+ /* If this is a known ABI section, ELF section type and flags may
+ have been set up when OSEC was created. For normal sections we
+ allow the user to override the type and flags other than
+ SHF_MASKOS and SHF_MASKPROC. */
+ if (elf_section_type (osec) == SHT_PROGBITS
+ || elf_section_type (osec) == SHT_NOTE
+ || elf_section_type (osec) == SHT_NOBITS)
+ elf_section_type (osec) = SHT_NULL;
+ /* For objcopy and relocatable link, copy the ELF section type from
+ the input file if the BFD section flags are the same. (If they
+ are different the user may be doing something like
+ "objcopy --set-section-flags .text=alloc,data".) For a final
+ link allow some flags that the linker clears to differ. */
if (elf_section_type (osec) == SHT_NULL
&& (osec->flags == isec->flags
|| (final_link
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));
+ elf_section_flags (osec) = (elf_section_flags (isec)
+ & (SHF_MASKOS | SHF_MASKPROC));
/* Copy sh_info from input for mbind section. */
if ((elf_tdata (ibfd)->has_gnu_osabi & elf_gnu_osabi_mbind) != 0
elf_section_flags (s->output_section) &= ~SHF_GROUP;
elf_group_name (s->output_section) = NULL;
}
- /* Conversely, if the member section is not being output
- but the SHT_GROUP section is, then adjust its size. */
- else if (s->output_section == discarded
- && isec->output_section != discarded)
+ else
{
struct bfd_elf_section_data *elf_sec = elf_section_data (s);
- removed += 4;
- if (elf_sec->rel.hdr != NULL
- && (elf_sec->rel.hdr->sh_flags & SHF_GROUP) != 0)
- removed += 4;
- if (elf_sec->rela.hdr != NULL
- && (elf_sec->rela.hdr->sh_flags & SHF_GROUP) != 0)
- removed += 4;
+ if (s->output_section == discarded
+ && isec->output_section != discarded)
+ {
+ /* Conversely, if the member section is not being
+ output but the SHT_GROUP section is, then adjust
+ its size. */
+ removed += 4;
+ if (elf_sec->rel.hdr != NULL
+ && (elf_sec->rel.hdr->sh_flags & SHF_GROUP) != 0)
+ removed += 4;
+ if (elf_sec->rela.hdr != NULL
+ && (elf_sec->rela.hdr->sh_flags & SHF_GROUP) != 0)
+ removed += 4;
+ }
+ else
+ {
+ /* Also adjust for zero-sized relocation member
+ section. */
+ if (elf_sec->rel.hdr != NULL
+ && elf_sec->rel.hdr->sh_size == 0)
+ removed += 4;
+ if (elf_sec->rela.hdr != NULL
+ && elf_sec->rela.hdr->sh_size == 0)
+ removed += 4;
+ }
}
s = elf_next_in_group (s);
if (s == first)
int relocatable_p)
{
const struct elf_backend_data *bed;
- int symcount;
+ unsigned int symcount;
asymbol **syms;
struct elf_strtab_hash *stt;
Elf_Internal_Shdr *symtab_hdr;
bfd_byte *outbound_shndx;
unsigned long outbound_syms_index;
unsigned long outbound_shndx_index;
- int idx;
+ unsigned int idx;
unsigned int num_locals;
- bfd_size_type amt;
+ size_t amt;
bfd_boolean name_local_sections;
if (!elf_map_symbols (abfd, &num_locals))
symstrtab_hdr->sh_type = SHT_STRTAB;
/* Allocate buffer to swap out the .strtab section. */
- symstrtab = (struct elf_sym_strtab *) bfd_malloc2 (symcount + 1,
- sizeof (*symstrtab));
- if (symstrtab == NULL)
+ if (_bfd_mul_overflow (symcount + 1, sizeof (*symstrtab), &amt)
+ || (symstrtab = (struct elf_sym_strtab *) bfd_malloc (amt)) == NULL)
{
+ bfd_set_error (bfd_error_no_memory);
_bfd_elf_strtab_free (stt);
return FALSE;
}
- outbound_syms = (bfd_byte *) bfd_alloc2 (abfd, 1 + symcount,
- bed->s->sizeof_sym);
- if (outbound_syms == NULL)
+ if (_bfd_mul_overflow (symcount + 1, bed->s->sizeof_sym, &amt)
+ || (outbound_syms = (bfd_byte *) bfd_alloc (abfd, amt)) == NULL)
{
-error_return:
- _bfd_elf_strtab_free (stt);
+ error_no_mem:
+ bfd_set_error (bfd_error_no_memory);
+ error_return:
free (symstrtab);
+ _bfd_elf_strtab_free (stt);
return FALSE;
}
symtab_hdr->contents = outbound_syms;
symtab_shndx_hdr = & elf_symtab_shndx_list (abfd)->hdr;
if (symtab_shndx_hdr->sh_name != 0)
{
- 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 (_bfd_mul_overflow (symcount + 1,
+ sizeof (Elf_External_Sym_Shndx), &amt))
+ goto error_no_mem;
+ outbound_shndx = (bfd_byte *) bfd_zalloc (abfd, amt);
if (outbound_shndx == NULL)
goto error_return;
if (elf_symtab_shndx_list (abfd))
shndx = elf_symtab_shndx_list (abfd)->ndx;
break;
- default:
+ case SHN_COMMON:
+ case SHN_ABS:
shndx = SHN_ABS;
break;
+ default:
+ if (shndx >= SHN_LOPROC && shndx <= SHN_HIOS)
+ {
+ if (bed->symbol_section_index)
+ shndx = bed->symbol_section_index (abfd, type_ptr);
+ /* Otherwise just leave the index alone. */
+ }
+ else
+ {
+ if (shndx > SHN_HIOS && shndx < SHN_HIRESERVE)
+ _bfd_error_handler (_("%pB: \
+Unable to handle section index %x in ELF symbol. Using ABS instead."),
+ abfd, shndx);
+ shndx = SHN_ABS;
+ }
+ break;
}
}
else
}
long
-_bfd_elf_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED,
- sec_ptr asect)
+_bfd_elf_get_reloc_upper_bound (bfd *abfd, sec_ptr asect)
{
+ if (asect->reloc_count != 0)
+ {
+ /* Sanity check reloc section size. */
+ struct bfd_elf_section_data *d = elf_section_data (asect);
+ Elf_Internal_Shdr *rel_hdr = &d->this_hdr;
+ bfd_size_type ext_rel_size = rel_hdr->sh_size;
+ ufile_ptr filesize = bfd_get_file_size (abfd);
+
+ if (filesize != 0 && ext_rel_size > filesize)
+ {
+ bfd_set_error (bfd_error_file_truncated);
+ return -1;
+ }
+ }
+
#if SIZEOF_LONG == SIZEOF_INT
if (asect->reloc_count >= LONG_MAX / sizeof (arelent *))
{
long
_bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd)
{
- bfd_size_type count;
+ bfd_size_type count, ext_rel_size;
asection *s;
if (elf_dynsymtab (abfd) == 0)
}
count = 1;
+ ext_rel_size = 0;
for (s = abfd->sections; s != NULL; s = s->next)
if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
&& (elf_section_data (s)->this_hdr.sh_type == SHT_REL
|| elf_section_data (s)->this_hdr.sh_type == SHT_RELA))
{
+ ext_rel_size += s->size;
+ if (ext_rel_size < s->size)
+ {
+ bfd_set_error (bfd_error_file_truncated);
+ return -1;
+ }
count += s->size / elf_section_data (s)->this_hdr.sh_entsize;
if (count > LONG_MAX / sizeof (arelent *))
{
return -1;
}
}
+ if (count > 1)
+ {
+ /* Sanity check reloc section sizes. */
+ ufile_ptr filesize = bfd_get_file_size (abfd);
+ if (filesize != 0 && ext_rel_size > filesize)
+ {
+ bfd_set_error (bfd_error_file_truncated);
+ return -1;
+ }
+ }
return count * sizeof (arelent *);
}
{
bfd_byte *contents = NULL;
unsigned int freeidx = 0;
+ size_t amt;
if (elf_dynverref (abfd) != 0)
{
if (hdr->sh_info == 0
|| hdr->sh_info > hdr->sh_size / sizeof (Elf_External_Verneed))
{
-error_return_bad_verref:
+ error_return_bad_verref:
_bfd_error_handler
(_("%pB: .gnu.version_r invalid entry"), abfd);
bfd_set_error (bfd_error_bad_value);
-error_return_verref:
+ error_return_verref:
elf_tdata (abfd)->verref = NULL;
elf_tdata (abfd)->cverrefs = 0;
goto error_return;
}
- ufile_ptr filesize = bfd_get_file_size (abfd);
- if (filesize > 0 && filesize < hdr->sh_size)
- {
- /* PR 24708: Avoid attempts to allocate a ridiculous amount
- of memory. */
- bfd_set_error (bfd_error_no_memory);
- _bfd_error_handler
- /* xgettext:c-format */
- (_("error: %pB version reference section is too large (%#" PRIx64 " bytes)"),
- abfd, (uint64_t) hdr->sh_size);
- goto error_return_verref;
- }
- contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
- if (contents == NULL)
+ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0)
goto error_return_verref;
-
- if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size)
+ contents = _bfd_malloc_and_read (abfd, hdr->sh_size, hdr->sh_size);
+ if (contents == NULL)
goto error_return_verref;
- elf_tdata (abfd)->verref = (Elf_Internal_Verneed *)
- bfd_alloc2 (abfd, hdr->sh_info, sizeof (Elf_Internal_Verneed));
-
+ if (_bfd_mul_overflow (hdr->sh_info, sizeof (Elf_Internal_Verneed), &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ goto error_return_verref;
+ }
+ elf_tdata (abfd)->verref = (Elf_Internal_Verneed *) bfd_alloc (abfd, amt);
if (elf_tdata (abfd)->verref == NULL)
goto error_return_verref;
iverneed->vn_auxptr = NULL;
else
{
+ if (_bfd_mul_overflow (iverneed->vn_cnt,
+ sizeof (Elf_Internal_Vernaux), &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ goto error_return_verref;
+ }
iverneed->vn_auxptr = (struct elf_internal_vernaux *)
- bfd_alloc2 (abfd, iverneed->vn_cnt,
- sizeof (Elf_Internal_Vernaux));
+ bfd_alloc (abfd, amt);
if (iverneed->vn_auxptr == NULL)
goto error_return_verref;
}
goto error_return;
}
- contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
- if (contents == NULL)
+ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0)
goto error_return_verdef;
- if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
- || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size)
+ contents = _bfd_malloc_and_read (abfd, hdr->sh_size, hdr->sh_size);
+ if (contents == NULL)
goto error_return_verdef;
BFD_ASSERT (sizeof (Elf_External_Verdef)
else
freeidx = ++maxidx;
}
-
- elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *)
- bfd_zalloc2 (abfd, maxidx, sizeof (Elf_Internal_Verdef));
+ if (_bfd_mul_overflow (maxidx, sizeof (Elf_Internal_Verdef), &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ goto error_return_verdef;
+ }
+ elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) bfd_zalloc (abfd, amt);
if (elf_tdata (abfd)->verdef == NULL)
goto error_return_verdef;
iverdef->vd_auxptr = NULL;
else
{
+ if (_bfd_mul_overflow (iverdef->vd_cnt,
+ sizeof (Elf_Internal_Verdaux), &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ goto error_return_verdef;
+ }
iverdef->vd_auxptr = (struct elf_internal_verdaux *)
- bfd_alloc2 (abfd, iverdef->vd_cnt,
- sizeof (Elf_Internal_Verdaux));
+ bfd_alloc (abfd, amt);
if (iverdef->vd_auxptr == NULL)
goto error_return_verdef;
}
else
freeidx++;
- elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *)
- bfd_zalloc2 (abfd, freeidx, sizeof (Elf_Internal_Verdef));
+ if (_bfd_mul_overflow (freeidx, sizeof (Elf_Internal_Verdef), &amt))
+ {
+ bfd_set_error (bfd_error_file_too_big);
+ goto error_return;
+ }
+ elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) bfd_zalloc (abfd, amt);
if (elf_tdata (abfd)->verdef == NULL)
goto error_return;
return TRUE;
error_return:
- if (contents != NULL)
- free (contents);
+ free (contents);
return FALSE;
}
\f
filename_ptr, functionname_ptr,
line_ptr, discriminator_ptr,
dwarf_debug_sections,
- &elf_tdata (abfd)->dwarf2_find_line_info)
- || _bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
- filename_ptr, functionname_ptr,
- line_ptr))
+ &elf_tdata (abfd)->dwarf2_find_line_info))
+ return TRUE;
+
+ if (_bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset,
+ filename_ptr, functionname_ptr, line_ptr))
{
if (!*functionname_ptr)
_bfd_elf_find_function (abfd, symbols, section, offset,
hdr = &elf_section_data (section)->this_hdr;
if (hdr->sh_offset == (file_ptr) -1)
{
- /* We must compress this section. Write output to the buffer. */
- unsigned char *contents = hdr->contents;
- if ((offset + count) > hdr->sh_size
- || (section->flags & SEC_ELF_COMPRESS) == 0
- || contents == NULL)
- abort ();
+ unsigned char *contents;
+
+ if (bfd_section_is_ctf (section))
+ /* Nothing to do with this section: the contents are generated
+ later. */
+ return TRUE;
+
+ if ((section->flags & SEC_ELF_COMPRESS) == 0)
+ {
+ _bfd_error_handler
+ (_("%pB:%pA: error: attempting to write into an unallocated compressed section"),
+ abfd, section);
+ bfd_set_error (bfd_error_invalid_operation);
+ return FALSE;
+ }
+
+ if ((offset + count) > hdr->sh_size)
+ {
+ _bfd_error_handler
+ (_("%pB:%pA: error: attempting to write over the end of the section"),
+ abfd, section);
+
+ bfd_set_error (bfd_error_invalid_operation);
+ return FALSE;
+ }
+
+ contents = hdr->contents;
+ if (contents == NULL)
+ {
+ _bfd_error_handler
+ (_("%pB:%pA: error: attempting to write section into an empty buffer"),
+ abfd, section);
+
+ bfd_set_error (bfd_error_invalid_operation);
+ return FALSE;
+ }
+
memcpy (contents + offset, location, count);
return TRUE;
}
+
pos = hdr->sh_offset + offset;
if (bfd_seek (abfd, pos, SEEK_SET) != 0
|| bfd_bwrite (location, count, abfd) != count)
howto = bfd_reloc_type_lookup (abfd, code);
- if (areloc->howto->pcrel_offset != howto->pcrel_offset)
+ if (howto && areloc->howto->pcrel_offset != howto->pcrel_offset)
{
if (howto->pcrel_offset)
areloc->addend += areloc->address;
/* xgettext:c-format */
_bfd_error_handler (_("%pB: %s unsupported"),
abfd, areloc->howto->name);
- bfd_set_error (bfd_error_bad_value);
+ bfd_set_error (bfd_error_sorry);
return FALSE;
}
_bfd_elf_close_and_cleanup (bfd *abfd)
{
struct elf_obj_tdata *tdata = elf_tdata (abfd);
- if (bfd_get_format (abfd) == bfd_object && tdata != NULL)
+ if (tdata != NULL
+ && (bfd_get_format (abfd) == bfd_object
+ || bfd_get_format (abfd) == bfd_core))
{
if (elf_tdata (abfd)->o != NULL && elf_shstrtab (abfd) != NULL)
_bfd_elf_strtab_free (elf_shstrtab (abfd));
return elfcore_make_note_pseudosection (abfd, ".reg-aarch-pauth", note);
}
+static bfd_boolean
+elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-arc-v2", note);
+}
+
#if defined (HAVE_PRPSINFO_T)
typedef prpsinfo_t elfcore_psinfo_t;
#if defined (HAVE_PRPSINFO32_T) /* Sparc64 cross Sparc32 */
else
return TRUE;
+ case NT_ARC_V2:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_arc_v2 (abfd, note);
+ else
+ return TRUE;
+
case NT_ARM_VFP:
if (note->namesz == 6
&& strcmp (note->namedata, "LINUX") == 0)
case NT_NETBSDCORE_AUXV:
/* NetBSD-specific Elf Auxiliary Vector data. */
return elfcore_make_auxv_note_section (abfd, note, 4);
+#endif
+#ifdef NT_NETBSDCORE_LWPSTATUS
+ case NT_NETBSDCORE_LWPSTATUS:
+ return elfcore_make_note_pseudosection (abfd,
+ ".note.netbsdcore.lwpstatus",
+ note);
#endif
default:
break;
}
- /* As of March 2017 there are no other machine-independent notes
+ /* As of March 2020 there are no other machine-independent notes
defined for NetBSD core files. If the note type is less
than the start of the machine-dependent note types, we don't
understand it. */
/* On the Alpha, SPARC (32-bit and 64-bit), PT_GETREGS == mach+0 and
PT_GETFPREGS == mach+2. */
+ case bfd_arch_aarch64:
case bfd_arch_alpha:
case bfd_arch_sparc:
switch (note->type)
note_name, NT_ARM_PAC_MASK, aarch_pauth, size);
}
+char *
+elfcore_write_arc_v2 (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *arc_v2,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_ARC_V2, arc_v2, size);
+}
+
char *
elfcore_write_register_note (bfd *abfd,
char *buf,
return elfcore_write_aarch_sve (abfd, buf, bufsiz, data, size);
if (strcmp (section, ".reg-aarch-pauth") == 0)
return elfcore_write_aarch_pauth (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-arc-v2") == 0)
+ return elfcore_write_arc_v2 (abfd, buf, bufsiz, data, size);
return NULL;
}
GROKER_ELEMENT ("NetBSD-CORE", elfcore_grok_netbsd_note),
GROKER_ELEMENT ( "OpenBSD", elfcore_grok_openbsd_note),
GROKER_ELEMENT ("QNX", elfcore_grok_nto_note),
- GROKER_ELEMENT ("SPU/", elfcore_grok_spu_note)
+ GROKER_ELEMENT ("SPU/", elfcore_grok_spu_note),
+ GROKER_ELEMENT ("GNU", elfobj_grok_gnu_note)
};
#undef GROKER_ELEMENT
int i;
return TRUE;
}
-static bfd_boolean
+bfd_boolean
elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size,
size_t align)
{
if (bfd_seek (abfd, offset, SEEK_SET) != 0)
return FALSE;
- buf = (char *) bfd_malloc (size + 1);
+ buf = (char *) _bfd_malloc_and_read (abfd, size + 1, size);
if (buf == NULL)
return FALSE;
0-termintate the buffer so that string searches will not overflow. */
buf[size] = 0;
- if (bfd_bread (buf, size, abfd) != size
- || !elf_parse_notes (abfd, buf, size, offset, align))
+ if (!elf_parse_notes (abfd, buf, size, offset, align))
{
free (buf);
return FALSE;
/* 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;
+ offset = ((sec->size - address_size)
+ / bfd_octets_per_byte (abfd, sec) - offset);
}
return offset;
}
= BFD_FAKE_SECTION (_bfd_elf_large_com_section, &lcomm_sym,
"LARGE_COMMON", 0, SEC_IS_COMMON);
-void
-_bfd_elf_post_process_headers (bfd *abfd ATTRIBUTE_UNUSED,
- struct bfd_link_info *info ATTRIBUTE_UNUSED)
-{
-}
-
bfd_boolean
_bfd_elf_final_write_processing (bfd *abfd)
{
_bfd_error_handler (_("symbol type STT_GNU_IFUNC is unsupported"));
if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_unique)
_bfd_error_handler (_("symbol binding STB_GNU_UNIQUE is unsupported"));
- bfd_set_error (bfd_error_bad_value);
+ bfd_set_error (bfd_error_sorry);
return FALSE;
}
}
size = 1;
return size;
}
+
+/* Set to non-zero to enable some debug messages. */
+#define DEBUG_SECONDARY_RELOCS 0
+
+/* An internal-to-the-bfd-library only section type
+ used to indicate a cached secondary reloc section. */
+#define SHT_SECONDARY_RELOC (SHT_LOOS + SHT_RELA)
+
+/* Create a BFD section to hold a secondary reloc section. */
+
+bfd_boolean
+_bfd_elf_init_secondary_reloc_section (bfd * abfd,
+ Elf_Internal_Shdr *hdr,
+ const char * name,
+ unsigned int shindex)
+{
+ /* We only support RELA secondary relocs. */
+ if (hdr->sh_type != SHT_RELA)
+ return FALSE;
+
+#if DEBUG_SECONDARY_RELOCS
+ fprintf (stderr, "secondary reloc section %s encountered\n", name);
+#endif
+ hdr->sh_type = SHT_SECONDARY_RELOC;
+ return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex);
+}
+
+/* Read in any secondary relocs associated with SEC. */
+
+bfd_boolean
+_bfd_elf_slurp_secondary_reloc_section (bfd * abfd,
+ asection * sec,
+ asymbol ** symbols)
+{
+ const struct elf_backend_data * const ebd = get_elf_backend_data (abfd);
+ asection * relsec;
+ bfd_boolean result = TRUE;
+ bfd_vma (*r_sym) (bfd_vma);
+
+#if BFD_DEFAULT_TARGET_SIZE > 32
+ if (bfd_arch_bits_per_address (abfd) != 32)
+ r_sym = elf64_r_sym;
+ else
+#endif
+ r_sym = elf32_r_sym;
+
+ /* Discover if there are any secondary reloc sections
+ associated with SEC. */
+ for (relsec = abfd->sections; relsec != NULL; relsec = relsec->next)
+ {
+ Elf_Internal_Shdr * hdr = & elf_section_data (relsec)->this_hdr;
+
+ if (hdr->sh_type == SHT_SECONDARY_RELOC
+ && hdr->sh_info == (unsigned) elf_section_data (sec)->this_idx)
+ {
+ bfd_byte * native_relocs;
+ bfd_byte * native_reloc;
+ arelent * internal_relocs;
+ arelent * internal_reloc;
+ unsigned int i;
+ unsigned int entsize;
+ unsigned int symcount;
+ unsigned int reloc_count;
+ size_t amt;
+
+ if (ebd->elf_info_to_howto == NULL)
+ return FALSE;
+
+#if DEBUG_SECONDARY_RELOCS
+ fprintf (stderr, "read secondary relocs for %s from %s\n",
+ sec->name, relsec->name);
+#endif
+ entsize = hdr->sh_entsize;
+
+ native_relocs = bfd_malloc (hdr->sh_size);
+ if (native_relocs == NULL)
+ {
+ result = FALSE;
+ continue;
+ }
+
+ reloc_count = NUM_SHDR_ENTRIES (hdr);
+ if (_bfd_mul_overflow (reloc_count, sizeof (arelent), & amt))
+ {
+ free (native_relocs);
+ bfd_set_error (bfd_error_file_too_big);
+ result = FALSE;
+ continue;
+ }
+
+ internal_relocs = (arelent *) bfd_alloc (abfd, amt);
+ if (internal_relocs == NULL)
+ {
+ free (native_relocs);
+ result = FALSE;
+ continue;
+ }
+
+ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0
+ || (bfd_bread (native_relocs, hdr->sh_size, abfd)
+ != hdr->sh_size))
+ {
+ free (native_relocs);
+ /* The internal_relocs will be freed when
+ the memory for the bfd is released. */
+ result = FALSE;
+ continue;
+ }
+
+ symcount = bfd_get_symcount (abfd);
+
+ for (i = 0, internal_reloc = internal_relocs,
+ native_reloc = native_relocs;
+ i < reloc_count;
+ i++, internal_reloc++, native_reloc += entsize)
+ {
+ bfd_boolean res;
+ Elf_Internal_Rela rela;
+
+ ebd->s->swap_reloca_in (abfd, native_reloc, & rela);
+
+ /* The address of an ELF reloc is section relative for an object
+ file, and absolute for an executable file or shared library.
+ The address of a normal BFD reloc is always section relative,
+ and the address of a dynamic reloc is absolute.. */
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0)
+ internal_reloc->address = rela.r_offset;
+ else
+ internal_reloc->address = rela.r_offset - sec->vma;
+
+ if (r_sym (rela.r_info) == STN_UNDEF)
+ {
+ /* FIXME: This and the error case below mean that we
+ have a symbol on relocs that is not elf_symbol_type. */
+ internal_reloc->sym_ptr_ptr =
+ bfd_abs_section_ptr->symbol_ptr_ptr;
+ }
+ else if (r_sym (rela.r_info) > symcount)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): relocation %d has invalid symbol index %ld"),
+ abfd, sec, i, (long) r_sym (rela.r_info));
+ bfd_set_error (bfd_error_bad_value);
+ internal_reloc->sym_ptr_ptr =
+ bfd_abs_section_ptr->symbol_ptr_ptr;
+ result = FALSE;
+ }
+ else
+ {
+ asymbol **ps;
+
+ ps = symbols + r_sym (rela.r_info) - 1;
+
+ internal_reloc->sym_ptr_ptr = ps;
+ /* Make sure that this symbol is not removed by strip. */
+ (*ps)->flags |= BSF_KEEP;
+ }
+
+ internal_reloc->addend = rela.r_addend;
+
+ res = ebd->elf_info_to_howto (abfd, internal_reloc, & rela);
+ if (! res || internal_reloc->howto == NULL)
+ {
+#if DEBUG_SECONDARY_RELOCS
+ fprintf (stderr, "there is no howto associated with reloc %lx\n",
+ rela.r_info);
+#endif
+ result = FALSE;
+ }
+ }
+
+ free (native_relocs);
+ /* Store the internal relocs. */
+ elf_section_data (relsec)->sec_info = internal_relocs;
+ }
+ }
+
+ return result;
+}
+
+/* Set the ELF section header fields of an output secondary reloc section. */
+
+bfd_boolean
+_bfd_elf_copy_special_section_fields (const bfd * ibfd ATTRIBUTE_UNUSED,
+ bfd * obfd ATTRIBUTE_UNUSED,
+ const Elf_Internal_Shdr * isection,
+ Elf_Internal_Shdr * osection)
+{
+ asection * isec;
+ asection * osec;
+
+ if (isection == NULL)
+ return FALSE;
+
+ if (isection->sh_type != SHT_SECONDARY_RELOC)
+ return TRUE;
+
+ isec = isection->bfd_section;
+ if (isec == NULL)
+ return FALSE;
+
+ osec = osection->bfd_section;
+ if (osec == NULL)
+ return FALSE;
+
+ BFD_ASSERT (elf_section_data (osec)->sec_info == NULL);
+ elf_section_data (osec)->sec_info = elf_section_data (isec)->sec_info;
+ osection->sh_type = SHT_RELA;
+ osection->sh_link = elf_onesymtab (obfd);
+ if (osection->sh_link == 0)
+ {
+ /* There is no symbol table - we are hosed... */
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): link section cannot be set because the output file does not have a symbol table"),
+ obfd, osec);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ /* Find the output section that corresponds to the isection's sh_info link. */
+ if (isection->sh_info == 0
+ || isection->sh_info >= elf_numsections (ibfd))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): info section index is invalid"),
+ obfd, osec);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ isection = elf_elfsections (ibfd)[isection->sh_info];
+
+ if (isection == NULL
+ || isection->bfd_section == NULL
+ || isection->bfd_section->output_section == NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): info section index cannot be set because the section is not in the output"),
+ obfd, osec);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ osection->sh_info =
+ elf_section_data (isection->bfd_section->output_section)->this_idx;
+
+#if DEBUG_SECONDARY_RELOCS
+ fprintf (stderr, "update header of %s, sh_link = %u, sh_info = %u\n",
+ osec->name, osection->sh_link, osection->sh_info);
+#endif
+
+ return TRUE;
+}
+
+/* Write out a secondary reloc section. */
+
+bfd_boolean
+_bfd_elf_write_secondary_reloc_section (bfd *abfd, asection *sec)
+{
+ const struct elf_backend_data * const ebd = get_elf_backend_data (abfd);
+ bfd_vma addr_offset;
+ asection * relsec;
+ bfd_vma (*r_info) (bfd_vma, bfd_vma);
+ bfd_boolean result = TRUE;
+
+ if (sec == NULL)
+ return FALSE;
+
+#if BFD_DEFAULT_TARGET_SIZE > 32
+ if (bfd_arch_bits_per_address (abfd) != 32)
+ r_info = elf64_r_info;
+ else
+#endif
+ r_info = elf32_r_info;
+
+ /* The address of an ELF reloc is section relative for an object
+ file, and absolute for an executable file or shared library.
+ The address of a BFD reloc is always section relative. */
+ addr_offset = 0;
+ if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0)
+ addr_offset = sec->vma;
+
+ /* Discover if there are any secondary reloc sections
+ associated with SEC. */
+ for (relsec = abfd->sections; relsec != NULL; relsec = relsec->next)
+ {
+ const struct bfd_elf_section_data * const esd = elf_section_data (relsec);
+ Elf_Internal_Shdr * const hdr = (Elf_Internal_Shdr *) & esd->this_hdr;
+
+ if (hdr->sh_type == SHT_RELA
+ && hdr->sh_info == (unsigned) elf_section_data (sec)->this_idx)
+ {
+ asymbol * last_sym;
+ int last_sym_idx;
+ unsigned int reloc_count;
+ unsigned int idx;
+ arelent * src_irel;
+ bfd_byte * dst_rela;
+
+ if (hdr->contents != NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: secondary reloc section processed twice"),
+ abfd, relsec);
+ bfd_set_error (bfd_error_bad_value);
+ result = FALSE;
+ continue;
+ }
+
+ reloc_count = hdr->sh_size / hdr->sh_entsize;
+ if (reloc_count <= 0)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: secondary reloc section is empty!"),
+ abfd, relsec);
+ bfd_set_error (bfd_error_bad_value);
+ result = FALSE;
+ continue;
+ }
+
+ hdr->contents = bfd_alloc (abfd, hdr->sh_size);
+ if (hdr->contents == NULL)
+ continue;
+
+#if DEBUG_SECONDARY_RELOCS
+ fprintf (stderr, "write %u secondary relocs for %s from %s\n",
+ reloc_count, sec->name, relsec->name);
+#endif
+ last_sym = NULL;
+ last_sym_idx = 0;
+ dst_rela = hdr->contents;
+ src_irel = (arelent *) esd->sec_info;
+ if (src_irel == NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: internal relocs missing for secondary reloc section"),
+ abfd, relsec);
+ bfd_set_error (bfd_error_bad_value);
+ result = FALSE;
+ continue;
+ }
+
+ for (idx = 0; idx < reloc_count; idx++, dst_rela += hdr->sh_entsize)
+ {
+ Elf_Internal_Rela src_rela;
+ arelent *ptr;
+ asymbol *sym;
+ int n;
+
+ ptr = src_irel + idx;
+ if (ptr == NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: reloc table entry %u is empty"),
+ abfd, relsec, idx);
+ bfd_set_error (bfd_error_bad_value);
+ result = FALSE;
+ break;
+ }
+
+ if (ptr->sym_ptr_ptr == NULL)
+ {
+ /* FIXME: Is this an error ? */
+ n = 0;
+ }
+ else
+ {
+ sym = *ptr->sym_ptr_ptr;
+
+ if (sym == last_sym)
+ n = last_sym_idx;
+ else
+ {
+ n = _bfd_elf_symbol_from_bfd_symbol (abfd, & sym);
+ if (n < 0)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: secondary reloc %u references a missing symbol"),
+ abfd, relsec, idx);
+ bfd_set_error (bfd_error_bad_value);
+ result = FALSE;
+ n = 0;
+ }
+
+ last_sym = sym;
+ last_sym_idx = n;
+ }
+
+ if (sym->the_bfd != NULL
+ && sym->the_bfd->xvec != abfd->xvec
+ && ! _bfd_elf_validate_reloc (abfd, ptr))
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: secondary reloc %u references a deleted symbol"),
+ abfd, relsec, idx);
+ bfd_set_error (bfd_error_bad_value);
+ result = FALSE;
+ n = 0;
+ }
+ }
+
+ src_rela.r_offset = ptr->address + addr_offset;
+ if (ptr->howto == NULL)
+ {
+ _bfd_error_handler
+ /* xgettext:c-format */
+ (_("%pB(%pA): error: secondary reloc %u is of an unknown type"),
+ abfd, relsec, idx);
+ bfd_set_error (bfd_error_bad_value);
+ result = FALSE;
+ src_rela.r_info = r_info (0, 0);
+ }
+ else
+ src_rela.r_info = r_info (n, ptr->howto->type);
+ src_rela.r_addend = ptr->addend;
+ ebd->s->swap_reloca_out (abfd, &src_rela, dst_rela);
+ }
+ }
+ }
+
+ return result;
+}