/* 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;
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;
}
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);
}
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",
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)
*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;
++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
{
(*_bfd_error_handler)
(_("%B: section %A vma 0x%lx overlaps previous sections"),
- abfd, sec, (unsigned long) sec->lma);
+ abfd, sec, (unsigned long) sec->vma);
adjust = 0;
}
p->p_memsz += 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;
}
}
/* 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;
}
}
phdr_included = TRUE;
}
+ 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)
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;
}
}
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)
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,
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;
}
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;