/* ELF executable support for BFD.
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
return bfd_elf_make_generic_object (abfd);
}
-char *
+static 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 == 0
+ if (shstrtabsize + 1 <= 1
|| (shstrtab = bfd_alloc (abfd, shstrtabsize + 1)) == NULL
|| bfd_seek (abfd, offset, SEEK_SET) != 0)
shstrtab = NULL;
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_file_truncated);
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. */
+ i_shdrp[shindex]->sh_size = 0;
}
else
shstrtab[shstrtabsize] = '\0';
const bfd_byte *esym;
Elf_External_Sym_Shndx *alloc_extshndx;
Elf_External_Sym_Shndx *shndx;
+ Elf_Internal_Sym *alloc_intsym;
Elf_Internal_Sym *isym;
Elf_Internal_Sym *isymend;
const struct elf_backend_data *bed;
/* Read the symbols. */
alloc_ext = NULL;
alloc_extshndx = NULL;
+ alloc_intsym = NULL;
bed = get_elf_backend_data (ibfd);
extsym_size = bed->s->sizeof_sym;
amt = symcount * extsym_size;
if (intsym_buf == NULL)
{
- intsym_buf = bfd_malloc2 (symcount, sizeof (Elf_Internal_Sym));
+ alloc_intsym = bfd_malloc2 (symcount, sizeof (Elf_Internal_Sym));
+ intsym_buf = alloc_intsym;
if (intsym_buf == NULL)
goto out;
}
(*_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;
goto out;
}
if (! bfd_set_section_vma (abfd, newsect, hdr->sh_addr)
|| ! bfd_set_section_size (abfd, newsect, hdr->sh_size)
|| ! bfd_set_section_alignment (abfd, newsect,
- bfd_log2 ((bfd_vma) hdr->sh_addralign)))
+ bfd_log2 (hdr->sh_addralign)))
return FALSE;
flags = SEC_NO_FLAGS;
{ NULL, 0 }, /* 'p' */
{ NULL, 0 }, /* 'q' */
{ NULL, 0 }, /* 'r' */
- { STRING_COMMA_LEN ("stab") } /* 's' */
+ { STRING_COMMA_LEN ("stab") }, /* 's' */
+ { NULL, 0 }, /* 't' */
+ { NULL, 0 }, /* 'u' */
+ { NULL, 0 }, /* 'v' */
+ { NULL, 0 }, /* 'w' */
+ { NULL, 0 }, /* 'x' */
+ { NULL, 0 }, /* 'y' */
+ { STRING_COMMA_LEN ("zdebug") } /* 'z' */
};
if (name [0] == '.')
PT_NOTEs from the core files are currently not parsed using BFD. */
if (hdr->sh_type == SHT_NOTE)
{
- char *contents;
+ bfd_byte *contents;
- contents = bfd_malloc (hdr->sh_size);
- if (!contents)
+ if (!bfd_malloc_and_get_section (abfd, newsect, &contents))
return FALSE;
- if (!bfd_get_section_contents (abfd, hdr->bfd_section, contents, 0,
- hdr->sh_size)
- || !elf_parse_notes (abfd, contents, hdr->sh_size, -1))
- {
- free (contents);
- return FALSE;
- }
-
+ elf_parse_notes (abfd, (char *) contents, hdr->sh_size, -1);
free (contents);
}
if ((flags & SEC_ALLOC) != 0)
{
Elf_Internal_Phdr *phdr;
- unsigned int i;
+ unsigned int i, nload;
+
+ /* Some ELF linkers produce binaries with all the program header
+ p_paddr fields zero. If we have such a binary with more than
+ one PT_LOAD header, then leave the section lma equal to vma
+ so that we don't create sections with overlapping lma. */
+ phdr = elf_tdata (abfd)->phdr;
+ for (nload = 0, i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
+ if (phdr->p_paddr != 0)
+ break;
+ else if (phdr->p_type == PT_LOAD && phdr->p_memsz != 0)
+ ++nload;
+ if (i >= elf_elfheader (abfd)->e_phnum && nload > 1)
+ return TRUE;
- /* Look through the phdrs to see if we need to adjust the lma.
- If all the p_paddr fields are zero, we ignore them, since
- some ELF linkers produce such output. */
phdr = elf_tdata (abfd)->phdr;
for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
{
- if (phdr->p_paddr != 0)
- break;
- }
- if (i < elf_elfheader (abfd)->e_phnum)
- {
- phdr = elf_tdata (abfd)->phdr;
- for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++)
+ /* This section is part of this segment if its file
+ offset plus size lies within the segment's memory
+ span and, if the section is loaded, the extent of the
+ loaded data lies within the extent of the segment.
+
+ Note - we used to check the p_paddr field as well, and
+ refuse to set the LMA if it was 0. This is wrong
+ though, as a perfectly valid initialised segment can
+ have a p_paddr of zero. Some architectures, eg ARM,
+ place special significance on the address 0 and
+ executables need to be able to have a segment which
+ covers this address. */
+ if (phdr->p_type == PT_LOAD
+ && (bfd_vma) hdr->sh_offset >= phdr->p_offset
+ && (hdr->sh_offset + hdr->sh_size
+ <= phdr->p_offset + phdr->p_memsz)
+ && ((flags & SEC_LOAD) == 0
+ || (hdr->sh_offset + hdr->sh_size
+ <= phdr->p_offset + phdr->p_filesz)))
{
- /* This section is part of this segment if its file
- offset plus size lies within the segment's memory
- span and, if the section is loaded, the extent of the
- loaded data lies within the extent of the segment.
-
- Note - we used to check the p_paddr field as well, and
- refuse to set the LMA if it was 0. This is wrong
- though, as a perfectly valid initialised segment can
- have a p_paddr of zero. Some architectures, eg ARM,
- place special significance on the address 0 and
- executables need to be able to have a segment which
- covers this address. */
- if (phdr->p_type == PT_LOAD
- && (bfd_vma) hdr->sh_offset >= phdr->p_offset
- && (hdr->sh_offset + hdr->sh_size
- <= phdr->p_offset + phdr->p_memsz)
- && ((flags & SEC_LOAD) == 0
- || (hdr->sh_offset + hdr->sh_size
- <= phdr->p_offset + phdr->p_filesz)))
- {
- if ((flags & SEC_LOAD) == 0)
- newsect->lma = (phdr->p_paddr
- + hdr->sh_addr - phdr->p_vaddr);
- else
- /* We used to use the same adjustment for SEC_LOAD
- sections, but that doesn't work if the segment
- is packed with code from multiple VMAs.
- Instead we calculate the section LMA based on
- the segment LMA. It is assumed that the
- segment will contain sections with contiguous
- LMAs, even if the VMAs are not. */
- newsect->lma = (phdr->p_paddr
- + hdr->sh_offset - phdr->p_offset);
-
- /* With contiguous segments, we can't tell from file
- offsets whether a section with zero size should
- be placed at the end of one segment or the
- beginning of the next. Decide based on vaddr. */
- if (hdr->sh_addr >= phdr->p_vaddr
- && (hdr->sh_addr + hdr->sh_size
- <= phdr->p_vaddr + phdr->p_memsz))
- break;
- }
+ if ((flags & SEC_LOAD) == 0)
+ newsect->lma = (phdr->p_paddr
+ + hdr->sh_addr - phdr->p_vaddr);
+ else
+ /* We used to use the same adjustment for SEC_LOAD
+ sections, but that doesn't work if the segment
+ is packed with code from multiple VMAs.
+ Instead we calculate the section LMA based on
+ the segment LMA. It is assumed that the
+ segment will contain sections with contiguous
+ LMAs, even if the VMAs are not. */
+ newsect->lma = (phdr->p_paddr
+ + hdr->sh_offset - phdr->p_offset);
+
+ /* With contiguous segments, we can't tell from file
+ offsets whether a section with zero size should
+ be placed at the end of one segment or the
+ beginning of the next. Decide based on vaddr. */
+ if (hdr->sh_addr >= phdr->p_vaddr
+ && (hdr->sh_addr + hdr->sh_size
+ <= phdr->p_vaddr + phdr->p_memsz))
+ break;
}
}
}
return TRUE;
}
-/*
-INTERNAL_FUNCTION
- bfd_elf_find_section
-
-SYNOPSIS
- struct elf_internal_shdr *bfd_elf_find_section (bfd *abfd, char *name);
-
-DESCRIPTION
- Helper functions for GDB to locate the string tables.
- Since BFD hides string tables from callers, GDB needs to use an
- internal hook to find them. Sun's .stabstr, in particular,
- isn't even pointed to by the .stab section, so ordinary
- mechanisms wouldn't work to find it, even if we had some.
-*/
-
-struct elf_internal_shdr *
-bfd_elf_find_section (bfd *abfd, char *name)
-{
- Elf_Internal_Shdr **i_shdrp;
- char *shstrtab;
- unsigned int max;
- unsigned int i;
-
- i_shdrp = elf_elfsections (abfd);
- if (i_shdrp != NULL)
- {
- shstrtab = bfd_elf_get_str_section (abfd,
- elf_elfheader (abfd)->e_shstrndx);
- if (shstrtab != NULL)
- {
- max = elf_numsections (abfd);
- for (i = 1; i < max; i++)
- if (!strcmp (&shstrtab[i_shdrp[i]->sh_name], name))
- return i_shdrp[i];
- }
- }
- return 0;
-}
-
const char *const bfd_elf_section_type_names[] = {
"SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB",
"SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE",
fprintf (f, " %-20s ", name);
if (! stringp)
- fprintf (f, "0x%lx", (unsigned long) dyn.d_un.d_val);
+ {
+ fprintf (f, "0x");
+ bfd_fprintf_vma (abfd, f, dyn.d_un.d_val);
+ }
else
{
const char *string;
case bfd_print_symbol_more:
fprintf (file, "elf ");
bfd_fprintf_vma (abfd, file, symbol->value);
- fprintf (file, " %lx", (long) symbol->flags);
+ fprintf (file, " %lx", (unsigned long) symbol->flags);
break;
case bfd_print_symbol_all:
{
if (hdr->sh_entsize != bed->s->sizeof_sym)
return FALSE;
+ if (hdr->sh_info * hdr->sh_entsize > hdr->sh_size)
+ return FALSE;
BFD_ASSERT (elf_onesymtab (abfd) == 0);
elf_onesymtab (abfd) = shindex;
elf_tdata (abfd)->symtab_hdr = *hdr;
return TRUE;
case SHT_GROUP:
- /* We need a BFD section for objcopy and relocatable linking,
- and it's handy to have the signature available as the section
- name. */
if (! IS_VALID_GROUP_SECTION_HEADER (hdr))
return FALSE;
- name = group_signature (abfd, hdr);
- if (name == NULL)
- return FALSE;
if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
return FALSE;
if (hdr->contents != NULL)
{ NULL, 0, 0, 0, 0 }
};
+static const struct bfd_elf_special_section special_sections_z[] =
+{
+ { STRING_COMMA_LEN (".zdebug_line"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".zdebug_info"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".zdebug_abbrev"), 0, SHT_PROGBITS, 0 },
+ { STRING_COMMA_LEN (".zdebug_aranges"), 0, SHT_PROGBITS, 0 },
+ { NULL, 0, 0, 0, 0 }
+};
+
static const struct bfd_elf_special_section *special_sections[] =
{
special_sections_b, /* 'b' */
special_sections_r, /* 'r' */
special_sections_s, /* 's' */
special_sections_t, /* 't' */
+ NULL, /* 'u' */
+ NULL, /* 'v' */
+ NULL, /* 'w' */
+ NULL, /* 'x' */
+ NULL, /* 'y' */
+ special_sections_z /* 'z' */
};
const struct bfd_elf_special_section *
return NULL;
i = sec->name[1] - 'b';
- if (i < 0 || i > 't' - 'b')
+ if (i < 0 || i > 'z' - 'b')
return NULL;
spec = special_sections[i];
rel_hdr->sh_entsize = (use_rela_p
? bed->s->sizeof_rela
: bed->s->sizeof_rel);
- rel_hdr->sh_addralign = 1 << bed->s->log_file_align;
+ rel_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align;
rel_hdr->sh_flags = 0;
rel_hdr->sh_addr = 0;
rel_hdr->sh_size = 0;
this_hdr->sh_offset = 0;
this_hdr->sh_size = asect->size;
this_hdr->sh_link = 0;
- this_hdr->sh_addralign = 1 << asect->alignment_power;
+ this_hdr->sh_addralign = (bfd_vma) 1 << asect->alignment_power;
/* The sh_entsize and sh_info fields may have been set already by
copy_private_section_data. */
*failedptr = TRUE;
}
-/* Fill in the contents of a SHT_GROUP section. */
+/* Fill in the contents of a SHT_GROUP section. Called from
+ _bfd_elf_compute_section_file_positions for gas, objcopy, and
+ when ELF targets use the generic linker, ld. Called for ld -r
+ from bfd_elf_final_link. */
void
bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg)
{
bfd_boolean *failedptr = failedptrarg;
- unsigned long symindx;
asection *elt, *first;
unsigned char *loc;
bfd_boolean gas;
|| *failedptr)
return;
- symindx = 0;
- if (elf_group_id (sec) != NULL)
- symindx = elf_group_id (sec)->udata.i;
+ if (elf_section_data (sec)->this_hdr.sh_info == 0)
+ {
+ unsigned long symindx = 0;
+
+ /* elf_group_id will have been set up by objcopy and the
+ generic linker. */
+ if (elf_group_id (sec) != NULL)
+ symindx = elf_group_id (sec)->udata.i;
- if (symindx == 0)
+ 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);
+ symindx = elf_section_syms (abfd)[sec->index]->udata.i;
+ }
+ elf_section_data (sec)->this_hdr.sh_info = symindx;
+ }
+ else if (elf_section_data (sec)->this_hdr.sh_info == (unsigned int) -2)
{
- /* If called from the assembler, swap_out_syms will have set up
- elf_section_syms; If called for "ld -r", use target_index. */
- if (elf_section_syms (abfd) != NULL)
- symindx = elf_section_syms (abfd)[sec->index]->udata.i;
- else
- symindx = sec->target_index;
+ /* 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;
+ struct elf_link_hash_entry *h;
+
+ if (!elf_bad_symtab (igroup->owner))
+ {
+ Elf_Internal_Shdr *symtab_hdr;
+
+ symtab_hdr = &elf_tdata (igroup->owner)->symtab_hdr;
+ extsymoff = symtab_hdr->sh_info;
+ }
+ h = elf_sym_hashes (igroup->owner)[symndx - extsymoff];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ elf_section_data (sec)->this_hdr.sh_info = h->indx;
}
- elf_section_data (sec)->this_hdr.sh_info = symindx;
/* The contents won't be allocated for "ld -r" or objcopy. */
gas = TRUE;
asection *s;
unsigned int idx;
- loc -= 4;
s = elt;
- if (!gas)
- s = s->output_section;
- idx = 0;
- if (s != NULL)
- idx = elf_section_data (s)->this_idx;
- H_PUT_32 (abfd, idx, loc);
+ if (! elf_discarded_section (s))
+ {
+ loc -= 4;
+ if (!gas)
+ s = s->output_section;
+ idx = 0;
+ if (s != NULL)
+ idx = elf_section_data (s)->this_idx;
+ H_PUT_32 (abfd, idx, loc);
+ }
elt = elf_next_in_group (elt);
if (elt == first)
break;
}
/* Don't output section symbols for sections that are not going to be
- output. Also, don't output section symbols for reloc and other
- special sections. */
+ output. */
static bfd_boolean
ignore_section_sym (bfd *abfd, asymbol *sym)
{
return ((sym->flags & BSF_SECTION_SYM) != 0
- && (sym->value != 0
- || (sym->section->owner != abfd
- && (sym->section->output_section->owner != abfd
- || sym->section->output_offset != 0))));
+ && !(sym->section->owner == abfd
+ || (sym->section->output_section->owner == abfd
+ && sym->section->output_offset == 0)));
}
static bfd_boolean
asymbol *sym = syms[idx];
if ((sym->flags & BSF_SECTION_SYM) != 0
+ && sym->value == 0
&& !ignore_section_sym (abfd, sym))
{
asection *sec = sym->section;
file_ptr offset,
bfd_boolean align)
{
- if (align)
- {
- unsigned int al;
-
- al = i_shdrp->sh_addralign;
- if (al > 1)
- offset = BFD_ALIGN (offset, al);
- }
+ if (align && i_shdrp->sh_addralign > 1)
+ offset = BFD_ALIGN (offset, i_shdrp->sh_addralign);
i_shdrp->sh_offset = offset;
if (i_shdrp->bfd_section != NULL)
i_shdrp->bfd_section->filepos = offset;
++segs;
}
- if (info->relro)
+ if (info != NULL && info->relro)
{
/* We need a PT_GNU_RELRO segment. */
++segs;
segment. */
new_segment = TRUE;
}
- else if (BFD_ALIGN (last_hdr->lma + last_size, maxpagesize)
- < BFD_ALIGN (hdr->lma, maxpagesize))
+ /* In the next test we have to be careful when last_hdr->lma is close
+ to the end of the address space. If the aligned address wraps
+ around to the start of the address space, then there are no more
+ pages left in memory and it is OK to assume that the current
+ section can be included in the current segment. */
+ else if ((BFD_ALIGN (last_hdr->lma + last_size, maxpagesize) + maxpagesize
+ > last_hdr->lma)
+ && (BFD_ALIGN (last_hdr->lma + last_size, maxpagesize) + maxpagesize
+ <= hdr->lma))
{
/* If putting this section in this segment would force us to
skip a page in the segment, then we need a new segment. */
}
/* Allow interested parties a chance to override our decision. */
- if (last_hdr && info->callbacks->override_segment_assignment)
- new_segment = info->callbacks->override_segment_assignment (info, abfd, hdr, last_hdr, new_segment);
+ if (last_hdr != NULL
+ && info != NULL
+ && info->callbacks->override_segment_assignment != NULL)
+ new_segment
+ = info->callbacks->override_segment_assignment (info, abfd, hdr,
+ last_hdr,
+ new_segment);
if (! new_segment)
{
pm = &m->next;
}
- if (info->relro)
+ if (info != NULL && info->relro)
{
for (m = mfirst; m != NULL; m = m->next)
{
bfd_size_type maxpagesize;
unsigned int alloc;
unsigned int i, j;
+ bfd_vma header_pad = 0;
if (link_info == NULL
- && !elf_modify_segment_map (abfd, link_info, FALSE))
+ && !_bfd_elf_map_sections_to_segments (abfd, link_info))
return FALSE;
alloc = 0;
for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
- ++alloc;
+ {
+ ++alloc;
+ if (m->header_size)
+ header_pad = m->header_size;
+ }
elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr;
elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr;
return TRUE;
}
- phdrs = bfd_alloc2 (abfd, alloc, sizeof (Elf_Internal_Phdr));
+ /* We're writing the size in elf_tdata (abfd)->program_header_size,
+ see assign_file_positions_except_relocs, so make sure we have
+ that amount allocated, with trailing space cleared.
+ The variable alloc contains the computed need, while elf_tdata
+ (abfd)->program_header_size contains the size used for the
+ layout.
+ 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_tdata (abfd)->program_header_size % bed->s->sizeof_phdr
+ == 0);
+ phdrs = bfd_zalloc2 (abfd,
+ (elf_tdata (abfd)->program_header_size
+ / bed->s->sizeof_phdr),
+ sizeof (Elf_Internal_Phdr));
elf_tdata (abfd)->phdr = phdrs;
if (phdrs == NULL)
return FALSE;
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_tdata (abfd)->segment_map, p = phdrs, j = 0;
m != NULL;
elf_section_type (m->sections[i]) = SHT_NOBITS;
/* Find out whether this segment contains any loadable
- sections. If the first section isn't loadable, the same
- holds for any other sections. */
- i = 0;
- while (elf_section_type (m->sections[i]) == SHT_NOBITS)
- {
- /* If a segment starts with .tbss, we need to look
- at the next section to decide whether the segment
- has any loadable sections. */
- if ((elf_section_flags (m->sections[i]) & SHF_TLS) == 0
- || ++i >= m->count)
- {
- no_contents = TRUE;
- break;
- }
- }
+ sections. */
+ no_contents = TRUE;
+ for (i = 0; i < m->count; i++)
+ if (elf_section_type (m->sections[i]) != SHT_NOBITS)
+ {
+ no_contents = FALSE;
+ break;
+ }
off_adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align);
off += off_adjust;
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;
+ }
}
if (p->p_type == PT_LOAD
this_hdr = &elf_section_data (sec)->this_hdr;
align = (bfd_size_type) 1 << bfd_get_section_alignment (abfd, sec);
- if (p->p_type == PT_LOAD
- || p->p_type == PT_TLS)
- {
- bfd_signed_vma adjust = sec->lma - (p->p_paddr + p->p_memsz);
-
- if (this_hdr->sh_type != SHT_NOBITS
+ if ((p->p_type == PT_LOAD
+ || p->p_type == PT_TLS)
+ && (this_hdr->sh_type != SHT_NOBITS
|| ((this_hdr->sh_flags & SHF_ALLOC) != 0
&& ((this_hdr->sh_flags & SHF_TLS) == 0
- || p->p_type == PT_TLS)))
+ || p->p_type == PT_TLS))))
+ {
+ bfd_signed_vma adjust = sec->vma - (p->p_vaddr + p->p_memsz);
+
+ if (adjust < 0)
{
- if (adjust < 0)
- {
- (*_bfd_error_handler)
- (_("%B: section %A lma 0x%lx overlaps previous sections"),
- abfd, sec, (unsigned long) sec->lma);
- adjust = 0;
- }
- p->p_memsz += adjust;
+ (*_bfd_error_handler)
+ (_("%B: section %A vma 0x%lx overlaps previous sections"),
+ abfd, sec, (unsigned long) sec->vma);
+ adjust = 0;
+ }
+ p->p_memsz += adjust;
- if (this_hdr->sh_type != SHT_NOBITS)
- {
- off += adjust;
- p->p_filesz += adjust;
- }
+ if (this_hdr->sh_type != SHT_NOBITS)
+ {
+ off += adjust;
+ p->p_filesz += adjust;
}
}
m != NULL;
m = m->next, p++)
{
- if (m->count != 0)
+ if (p->p_type == PT_GNU_RELRO)
+ {
+ const Elf_Internal_Phdr *lp;
+
+ BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs);
+
+ if (link_info != NULL)
+ {
+ /* During linking the range of the RELRO segment is passed
+ in link_info. */
+ for (lp = phdrs; lp < phdrs + count; ++lp)
+ {
+ if (lp->p_type == PT_LOAD
+ && lp->p_vaddr >= link_info->relro_start
+ && lp->p_vaddr < link_info->relro_end
+ && lp->p_vaddr + lp->p_filesz >= link_info->relro_end)
+ break;
+ }
+ }
+ else
+ {
+ /* Otherwise we are copying an executable or shared
+ library, but we need to use the same linker logic. */
+ for (lp = phdrs; lp < phdrs + count; ++lp)
+ {
+ if (lp->p_type == PT_LOAD
+ && lp->p_paddr == p->p_paddr)
+ break;
+ }
+ }
+
+ if (lp < phdrs + count)
+ {
+ p->p_vaddr = lp->p_vaddr;
+ p->p_paddr = lp->p_paddr;
+ p->p_offset = lp->p_offset;
+ if (link_info != NULL)
+ p->p_filesz = link_info->relro_end - lp->p_vaddr;
+ else if (m->p_size_valid)
+ p->p_filesz = m->p_size;
+ else
+ abort ();
+ p->p_memsz = p->p_filesz;
+ p->p_align = 1;
+ p->p_flags = (lp->p_flags & ~PF_W);
+ }
+ else if (link_info != NULL)
+ {
+ memset (p, 0, sizeof *p);
+ p->p_type = PT_NULL;
+ }
+ else
+ abort ();
+ }
+ else if (m->count != 0)
{
if (p->p_type != PT_LOAD
&& (p->p_type != PT_NOTE
p->p_filesz = sect->filepos - m->sections[0]->filepos;
if (hdr->sh_type != SHT_NOBITS)
p->p_filesz += hdr->sh_size;
-
- if (p->p_type == PT_GNU_RELRO)
- {
- /* When we get here, we are copying executable
- or shared library. But we need to use the same
- linker logic. */
- Elf_Internal_Phdr *lp;
-
- for (lp = phdrs; lp < phdrs + count; ++lp)
- {
- if (lp->p_type == PT_LOAD
- && lp->p_paddr == p->p_paddr)
- break;
- }
-
- if (lp < phdrs + count)
- {
- /* We should use p_size if it is valid since it
- may contain the first few bytes of the next
- SEC_ALLOC section. */
- if (m->p_size_valid)
- p->p_filesz = m->p_size;
- else
- abort ();
- p->p_vaddr = lp->p_vaddr;
- p->p_offset = lp->p_offset;
- p->p_memsz = p->p_filesz;
- p->p_align = 1;
- }
- else
- abort ();
- }
- else
- p->p_offset = m->sections[0]->filepos;
+ p->p_offset = m->sections[0]->filepos;
}
}
- else
+ else if (m->includes_filehdr)
{
- 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;
- }
- else if (p->p_type == PT_GNU_RELRO)
- {
- Elf_Internal_Phdr *lp;
-
- for (lp = phdrs; lp < phdrs + count; ++lp)
- {
- if (lp->p_type == PT_LOAD
- && lp->p_vaddr <= link_info->relro_end
- && lp->p_vaddr >= link_info->relro_start
- && (lp->p_vaddr + lp->p_filesz
- >= link_info->relro_end))
- break;
- }
-
- if (lp < phdrs + count
- && link_info->relro_end > lp->p_vaddr)
- {
- p->p_vaddr = lp->p_vaddr;
- p->p_paddr = lp->p_paddr;
- p->p_offset = lp->p_offset;
- p->p_filesz = link_info->relro_end - lp->p_vaddr;
- p->p_memsz = p->p_filesz;
- p->p_align = 1;
- p->p_flags = (lp->p_flags & ~PF_W);
- }
- else
- {
- memset (p, 0, sizeof *p);
- p->p_type = PT_NULL;
- }
- }
+ 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;
}
}
unsigned int i;
unsigned int num_segments;
bfd_boolean phdr_included = FALSE;
+ bfd_boolean p_paddr_valid;
bfd_vma maxpagesize;
struct elf_segment_map *phdr_adjust_seg = NULL;
unsigned int phdr_adjust_num = 0;
for (section = ibfd->sections; section != NULL; section = section->next)
section->segment_mark = FALSE;
+ /* The Solaris linker creates program headers in which all the
+ p_paddr fields are zero. When we try to objcopy or strip such a
+ file, we get confused. Check for this case, and if we find it
+ don't set the p_paddr_valid fields. */
+ p_paddr_valid = FALSE;
+ for (i = 0, segment = elf_tdata (ibfd)->phdr;
+ i < num_segments;
+ i++, segment++)
+ if (segment->p_paddr != 0)
+ {
+ p_paddr_valid = TRUE;
+ break;
+ }
+
/* Scan through the segments specified in the program header
of the input BFD. For this first scan we look for overlaps
in the loadable segments. These can be created by weird
if (!first_section || first_section->output_section != NULL)
{
map->p_paddr = segment->p_paddr;
- map->p_paddr_valid = 1;
+ map->p_paddr_valid = p_paddr_valid;
}
/* Determine if this segment contains the ELF file header
pointers that we are interested in. As these sections get assigned
to a segment, they are removed from this array. */
- /* Gcc 2.96 miscompiles this code on mips. Don't do casting here
- to work around this long long bug. */
sections = bfd_malloc2 (section_count, sizeof (asection *));
if (sections == NULL)
return FALSE;
We try to catch that case here, and set it to the
correct value. Note - some backends require that
p_paddr be left as zero. */
- if (segment->p_paddr == 0
+ if (!p_paddr_valid
&& segment->p_vaddr != 0
&& !bed->want_p_paddr_set_to_zero
&& isec == 0
*pointer_to_map = map;
pointer_to_map = &map->next;
- if (!bed->want_p_paddr_set_to_zero
+ if (p_paddr_valid
+ && !bed->want_p_paddr_set_to_zero
&& matching_lma != map->p_paddr
- && !map->includes_filehdr && !map->includes_phdrs)
+ && !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. */
/* Offset the segment physical address from the lma
to allow for space taken up by elf headers. */
if (map->includes_filehdr)
- map->p_paddr -= iehdr->e_ehsize;
+ {
+ if (map->p_paddr >= iehdr->e_ehsize)
+ map->p_paddr -= iehdr->e_ehsize;
+ else
+ {
+ map->includes_filehdr = FALSE;
+ map->includes_phdrs = FALSE;
+ }
+ }
if (map->includes_phdrs)
{
- map->p_paddr -= iehdr->e_phnum * iehdr->e_phentsize;
-
- /* iehdr->e_phnum is just an estimate of the number
- of program headers that we will need. Make a note
- here of the number we used and the segment we chose
- to hold these headers, so that we can adjust the
- offset when we know the correct value. */
- phdr_adjust_num = iehdr->e_phnum;
- phdr_adjust_seg = map;
+ if (map->p_paddr >= iehdr->e_phnum * iehdr->e_phentsize)
+ {
+ map->p_paddr -= iehdr->e_phnum * iehdr->e_phentsize;
+
+ /* iehdr->e_phnum is just an estimate of the number
+ of program headers that we will need. Make a note
+ here of the number we used and the segment we chose
+ to hold these headers, so that we can adjust the
+ offset when we know the correct value. */
+ phdr_adjust_num = iehdr->e_phnum;
+ phdr_adjust_seg = map;
+ }
+ else
+ map->includes_phdrs = FALSE;
}
}
map->p_flags = segment->p_flags;
map->p_flags_valid = 1;
map->p_paddr = suggested_lma;
- map->p_paddr_valid = 1;
+ map->p_paddr_valid = p_paddr_valid;
map->includes_filehdr = 0;
map->includes_phdrs = 0;
}
free (sections);
}
- /* The Solaris linker creates program headers in which all the
- p_paddr fields are zero. When we try to objcopy or strip such a
- file, we get confused. Check for this case, and if we find it
- reset the p_paddr_valid fields. */
- for (map = map_first; map != NULL; map = map->next)
- if (map->p_paddr != 0)
- break;
- if (map == NULL)
- for (map = map_first; map != NULL; map = map->next)
- map->p_paddr_valid = 0;
-
elf_tdata (obfd)->segment_map = map_first;
/* If we had to estimate the number of program headers that were
unsigned int i;
unsigned int num_segments;
bfd_boolean phdr_included = FALSE;
+ bfd_boolean p_paddr_valid;
iehdr = elf_elfheader (ibfd);
map_first = NULL;
pointer_to_map = &map_first;
+ /* If all the segment p_paddr fields are zero, don't set
+ map->p_paddr_valid. */
+ p_paddr_valid = FALSE;
num_segments = elf_elfheader (ibfd)->e_phnum;
+ for (i = 0, segment = elf_tdata (ibfd)->phdr;
+ i < num_segments;
+ i++, segment++)
+ if (segment->p_paddr != 0)
+ {
+ p_paddr_valid = TRUE;
+ break;
+ }
+
for (i = 0, segment = elf_tdata (ibfd)->phdr;
i < num_segments;
i++, segment++)
map->p_flags = segment->p_flags;
map->p_flags_valid = 1;
map->p_paddr = segment->p_paddr;
- map->p_paddr_valid = 1;
+ map->p_paddr_valid = p_paddr_valid;
map->p_align = segment->p_align;
map->p_align_valid = 1;
map->p_vaddr_offset = 0;
phdr_included = TRUE;
}
- if (!map->includes_phdrs && !map->includes_filehdr)
+ if (map->includes_filehdr && first_section)
+ /* We need to keep the space used by the headers fixed. */
+ map->header_size = first_section->vma - segment->p_vaddr;
+
+ if (!map->includes_phdrs
+ && !map->includes_filehdr
+ && map->p_paddr_valid)
/* There is some other padding before the first section. */
map->p_vaddr_offset = ((lowest_section ? lowest_section->lma : 0)
- segment->p_paddr);
if (elf_section_flags (isec) & SHF_GROUP)
elf_section_flags (osec) |= SHF_GROUP;
elf_next_in_group (osec) = elf_next_in_group (isec);
- elf_group_name (osec) = elf_group_name (isec);
+ elf_section_data (osec)->group = elf_section_data (isec)->group;
}
}
symtab_hdr->sh_entsize = bed->s->sizeof_sym;
symtab_hdr->sh_size = symtab_hdr->sh_entsize * (symcount + 1);
symtab_hdr->sh_info = elf_num_locals (abfd) + 1;
- symtab_hdr->sh_addralign = 1 << bed->s->log_file_align;
+ symtab_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align;
symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr;
symstrtab_hdr->sh_type = SHT_STRTAB;
if (type == STT_OBJECT)
sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_COMMON);
else
-#else
- sym.st_info = ELF_ST_INFO (STB_GLOBAL, type);
#endif
+ 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)
ret = sizeof (arelent *);
for (s = abfd->sections; s != NULL; s = s->next)
- if ((s->flags & SEC_LOAD) != 0
- && elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+ 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))
ret += ((s->size / elf_section_data (s)->this_hdr.sh_entsize)
ret = 0;
for (s = abfd->sections; s != NULL; s = s->next)
{
- if ((s->flags & SEC_LOAD) != 0
- && elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd)
+ 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))
{
return elfcore_make_note_pseudosection (abfd, ".reg-ppc-vmx", note);
}
+static bfd_boolean
+elfcore_grok_ppc_vsx (bfd *abfd, Elf_Internal_Note *note)
+{
+ return elfcore_make_note_pseudosection (abfd, ".reg-ppc-vsx", note);
+}
#if defined (HAVE_PRPSINFO_T)
typedef prpsinfo_t elfcore_psinfo_t;
/* Make a ".module/xxxxxxxx" section. */
/* module_info.base_address */
base_addr = bfd_get_32 (abfd, note->descdata + 4);
- sprintf (buf, ".module/%08lx", (long) base_addr);
+ sprintf (buf, ".module/%08lx", (unsigned long) base_addr);
len = strlen (buf) + 1;
name = bfd_alloc (abfd, len);
else
return TRUE;
+ case NT_PPC_VSX:
+ if (note->namesz == 6
+ && strcmp (note->namedata, "LINUX") == 0)
+ return elfcore_grok_ppc_vsx (abfd, note);
+ else
+ return TRUE;
+
case NT_PRPSINFO:
case NT_PSINFO:
if (bed->elf_backend_grok_psinfo)
note_name, NT_PPC_VMX, ppc_vmx, size);
}
+char *
+elfcore_write_ppc_vsx (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const void *ppc_vsx,
+ int size)
+{
+ char *note_name = "LINUX";
+ return elfcore_write_note (abfd, buf, bufsiz,
+ note_name, NT_PPC_VSX, ppc_vsx, size);
+}
+
+char *
+elfcore_write_register_note (bfd *abfd,
+ char *buf,
+ int *bufsiz,
+ const char *section,
+ const void *data,
+ int size)
+{
+ if (strcmp (section, ".reg2") == 0)
+ return elfcore_write_prfpreg (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-xfp") == 0)
+ return elfcore_write_prxfpreg (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-vmx") == 0)
+ return elfcore_write_ppc_vmx (abfd, buf, bufsiz, data, size);
+ if (strcmp (section, ".reg-ppc-vsx") == 0)
+ return elfcore_write_ppc_vsx (abfd, buf, bufsiz, data, size);
+ return NULL;
+}
+
static bfd_boolean
elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset)
{
Elf_External_Note *xnp = (Elf_External_Note *) p;
Elf_Internal_Note in;
+ if (offsetof (Elf_External_Note, name) > buf - p + size)
+ return FALSE;
+
in.type = H_GET_32 (abfd, xnp->type);
in.namesz = H_GET_32 (abfd, xnp->namesz);
in.namedata = xnp->name;
+ if (in.namesz > buf - in.namedata + size)
+ return FALSE;
in.descsz = H_GET_32 (abfd, xnp->descsz);
in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4);
in.descpos = offset + (in.descdata - buf);
+ if (in.descsz != 0
+ && (in.descdata >= buf + size
+ || in.descsz > buf - in.descdata + size))
+ return FALSE;
switch (bfd_get_format (abfd))
{
relplt_name = bed->relplt_name;
if (relplt_name == NULL)
- relplt_name = bed->default_use_rela_p ? ".rela.plt" : ".rel.plt";
+ relplt_name = bed->rela_plts_and_copies_p ? ".rela.plt" : ".rel.plt";
relplt = bfd_get_section_by_name (abfd, relplt_name);
if (relplt == NULL)
return 0;
count = relplt->size / hdr->sh_entsize;
size = count * sizeof (asymbol);
p = relplt->relocation;
- for (i = 0; i < count; i++, p++)
+ for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
s = *ret = bfd_malloc (size);
names = (char *) (s + count);
p = relplt->relocation;
n = 0;
- for (i = 0; i < count; i++, p++)
+ for (i = 0; i < count; i++, p += bed->s->int_rels_per_ext_rel)
{
size_t len;
bfd_vma addr;
we are defining a symbol, ensure one of them is set. */
if ((s->flags & BSF_LOCAL) == 0)
s->flags |= BSF_GLOBAL;
+ s->flags |= BSF_SYNTHETIC;
s->section = plt;
s->value = addr - plt->vma;
s->name = names;