diff options
Diffstat (limited to 'binutils-2.24/bfd/elf-nacl.c')
-rw-r--r-- | binutils-2.24/bfd/elf-nacl.c | 355 |
1 files changed, 0 insertions, 355 deletions
diff --git a/binutils-2.24/bfd/elf-nacl.c b/binutils-2.24/bfd/elf-nacl.c deleted file mode 100644 index 944aa34d..00000000 --- a/binutils-2.24/bfd/elf-nacl.c +++ /dev/null @@ -1,355 +0,0 @@ -/* Native Client support for ELF - Copyright 2012, 2013 Free Software Foundation, Inc. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. */ - -#include "sysdep.h" -#include "bfd.h" -#include "libbfd.h" -#include "elf-bfd.h" -#include "elf-nacl.h" -#include "elf/common.h" -#include "elf/internal.h" - -static bfd_boolean -segment_executable (struct elf_segment_map *seg) -{ - if (seg->p_flags_valid) - return (seg->p_flags & PF_X) != 0; - else - { - /* The p_flags value has not been computed yet, - so we have to look through the sections. */ - unsigned int i; - for (i = 0; i < seg->count; ++i) - if (seg->sections[i]->flags & SEC_CODE) - return TRUE; - } - return FALSE; -} - -/* Determine if this segment is eligible to receive the file and program - headers. It must be read-only and non-executable. - Its first section must start far enough past the page boundary to - allow space for the headers. */ -static bfd_boolean -segment_eligible_for_headers (struct elf_segment_map *seg, - bfd_vma minpagesize, bfd_vma sizeof_headers) -{ - unsigned int i; - if (seg->count == 0 || seg->sections[0]->lma % minpagesize < sizeof_headers) - return FALSE; - for (i = 0; i < seg->count; ++i) - { - if ((seg->sections[i]->flags & (SEC_CODE|SEC_READONLY)) != SEC_READONLY) - return FALSE; - } - return TRUE; -} - - -/* We permute the segment_map to get BFD to do the file layout we want: - The first non-executable PT_LOAD segment appears first in the file - and contains the ELF file header and phdrs. */ -bfd_boolean -nacl_modify_segment_map (bfd *abfd, struct bfd_link_info *info) -{ - const struct elf_backend_data *const bed = get_elf_backend_data (abfd); - struct elf_segment_map **m = &elf_seg_map (abfd); - struct elf_segment_map **first_load = NULL; - struct elf_segment_map **last_load = NULL; - bfd_boolean moved_headers = FALSE; - int sizeof_headers; - - if (info != NULL && info->user_phdrs) - /* The linker script used PHDRS explicitly, so don't change what the - user asked for. */ - return TRUE; - - if (info != NULL) - /* We're doing linking, so evalute SIZEOF_HEADERS as in a linker script. */ - sizeof_headers = bfd_sizeof_headers (abfd, info); - else - { - /* We're not doing linking, so this is objcopy or suchlike. - We just need to collect the size of the existing headers. */ - struct elf_segment_map *seg; - sizeof_headers = bed->s->sizeof_ehdr; - for (seg = *m; seg != NULL; seg = seg->next) - sizeof_headers += bed->s->sizeof_phdr; - } - - while (*m != NULL) - { - struct elf_segment_map *seg = *m; - - if (seg->p_type == PT_LOAD) - { - bfd_boolean executable = segment_executable (seg); - - if (executable - && seg->count > 0 - && seg->sections[0]->vma % bed->minpagesize == 0) - { - asection *lastsec = seg->sections[seg->count - 1]; - bfd_vma end = lastsec->vma + lastsec->size; - if (end % bed->minpagesize != 0) - { - /* This is an executable segment that starts on a page - boundary but does not end on a page boundary. Fill - it out to a whole page with code fill (the tail of - the segment will not be within any section). Thus - the entire code segment can be mapped from the file - as whole pages and that mapping will contain only - valid instructions. - - To accomplish this, we must fake out the code in - assign_file_positions_for_load_sections (elf.c) so - that it advances past the rest of the final page, - rather than trying to put the next (unaligned, or - unallocated) section. We do this by appending a - dummy section record to this element in the segment - map. No such output section ever actually exists, - but this gets the layout logic to advance the file - positions past this partial page. Since we are - lying to BFD like this, nothing will ever know to - write the section contents. So we do that by hand - after the fact, in nacl_final_write_processing, below. */ - - struct elf_segment_map *newseg; - asection *sec; - struct bfd_elf_section_data *secdata; - - BFD_ASSERT (!seg->p_size_valid); - - secdata = bfd_zalloc (abfd, sizeof *secdata); - if (secdata == NULL) - return FALSE; - - sec = bfd_zalloc (abfd, sizeof *sec); - if (sec == NULL) - return FALSE; - - /* Fill in only the fields that actually affect the logic - in assign_file_positions_for_load_sections. */ - sec->vma = end; - sec->lma = lastsec->lma + lastsec->size; - sec->size = bed->minpagesize - (end % bed->minpagesize); - sec->flags = (SEC_ALLOC | SEC_LOAD - | SEC_READONLY | SEC_CODE | SEC_LINKER_CREATED); - sec->used_by_bfd = secdata; - - secdata->this_hdr.sh_type = SHT_PROGBITS; - secdata->this_hdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; - secdata->this_hdr.sh_addr = sec->vma; - secdata->this_hdr.sh_size = sec->size; - - newseg = bfd_alloc (abfd, - sizeof *newseg + ((seg->count + 1) - * sizeof (asection *))); - if (newseg == NULL) - return FALSE; - memcpy (newseg, seg, - sizeof *newseg + (seg->count * sizeof (asection *))); - newseg->sections[newseg->count++] = sec; - *m = seg = newseg; - } - } - - /* First, we're just finding the earliest PT_LOAD. - By the normal rules, this will be the lowest-addressed one. - We only have anything interesting to do if it's executable. */ - last_load = m; - if (first_load == NULL) - { - if (!executable) - goto next; - first_load = m; - } - /* Now that we've noted the first PT_LOAD, we're looking for - the first non-executable PT_LOAD with a nonempty p_filesz. */ - else if (!moved_headers - && segment_eligible_for_headers (seg, bed->minpagesize, - sizeof_headers)) - { - /* This is the one we were looking for! - - First, clear the flags on previous segments that - say they include the file header and phdrs. */ - struct elf_segment_map *prevseg; - for (prevseg = *first_load; - prevseg != seg; - prevseg = prevseg->next) - if (prevseg->p_type == PT_LOAD) - { - prevseg->includes_filehdr = 0; - prevseg->includes_phdrs = 0; - } - - /* This segment will include those headers instead. */ - seg->includes_filehdr = 1; - seg->includes_phdrs = 1; - - moved_headers = TRUE; - } - } - - next: - m = &seg->next; - } - - if (first_load != last_load && moved_headers) - { - /* Now swap the first and last PT_LOAD segments' - positions in segment_map. */ - struct elf_segment_map *first = *first_load; - struct elf_segment_map *last = *last_load; - *first_load = first->next; - first->next = last->next; - last->next = first; - } - - return TRUE; -} - -/* After nacl_modify_segment_map has done its work, the file layout has - been done as we wanted. But the PT_LOAD phdrs are no longer in the - proper order for the ELF rule that they must appear in ascending address - order. So find the two segments we swapped before, and swap them back. */ -bfd_boolean -nacl_modify_program_headers (bfd *abfd, struct bfd_link_info *info) -{ - struct elf_segment_map **m = &elf_seg_map (abfd); - Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr; - Elf_Internal_Phdr *p = phdr; - - if (info != NULL && info->user_phdrs) - /* The linker script used PHDRS explicitly, so don't change what the - user asked for. */ - return TRUE; - - /* Find the PT_LOAD that contains the headers (should be the first). */ - while (*m != NULL) - { - if ((*m)->p_type == PT_LOAD && (*m)->includes_filehdr) - break; - - m = &(*m)->next; - ++p; - } - - if (*m != NULL) - { - struct elf_segment_map **first_load_seg = m; - Elf_Internal_Phdr *first_load_phdr = p; - struct elf_segment_map **next_load_seg = NULL; - Elf_Internal_Phdr *next_load_phdr = NULL; - - /* Now move past that first one and find the PT_LOAD that should be - before it by address order. */ - - m = &(*m)->next; - ++p; - - while (*m != NULL) - { - if (p->p_type == PT_LOAD && p->p_vaddr < first_load_phdr->p_vaddr) - { - next_load_seg = m; - next_load_phdr = p; - break; - } - - m = &(*m)->next; - ++p; - } - - /* Swap their positions in the segment_map back to how they used to be. - The phdrs have already been set up by now, so we have to slide up - the earlier ones to insert the one that should be first. */ - if (next_load_seg != NULL) - { - Elf_Internal_Phdr move_phdr; - struct elf_segment_map *first_seg = *first_load_seg; - struct elf_segment_map *next_seg = *next_load_seg; - struct elf_segment_map *first_next = first_seg->next; - struct elf_segment_map *next_next = next_seg->next; - - if (next_load_seg == &first_seg->next) - { - *first_load_seg = next_seg; - next_seg->next = first_seg; - first_seg->next = next_next; - } - else - { - *first_load_seg = first_next; - *next_load_seg = next_next; - - first_seg->next = *next_load_seg; - *next_load_seg = first_seg; - - next_seg->next = *first_load_seg; - *first_load_seg = next_seg; - } - - move_phdr = *next_load_phdr; - memmove (first_load_phdr + 1, first_load_phdr, - (next_load_phdr - first_load_phdr) * sizeof move_phdr); - *first_load_phdr = move_phdr; - } - } - - return TRUE; -} - -void -nacl_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) -{ - struct elf_segment_map *seg; - for (seg = elf_seg_map (abfd); seg != NULL; seg = seg->next) - if (seg->p_type == PT_LOAD - && seg->count > 1 - && seg->sections[seg->count - 1]->owner == NULL) - { - /* This is a fake section added in nacl_modify_segment_map, above. - It's not a real BFD section, so nothing wrote its contents. - Now write out its contents. */ - - asection *sec = seg->sections[seg->count - 1]; - char *fill; - - BFD_ASSERT (sec->flags & SEC_LINKER_CREATED); - BFD_ASSERT (sec->flags & SEC_CODE); - BFD_ASSERT (sec->size > 0); - - fill = abfd->arch_info->fill (sec->size, bfd_big_endian (abfd), TRUE); - - if (fill == NULL - || bfd_seek (abfd, sec->filepos, SEEK_SET) != 0 - || bfd_bwrite (fill, sec->size, abfd) != sec->size) - { - /* We don't have a proper way to report an error here. So - instead fudge things so that elf_write_shdrs_and_ehdr will - fail. */ - elf_elfheader (abfd)->e_shoff = (file_ptr) -1; - } - - free (fill); - } -} |