Home | History | Annotate | Download | only in bfd
      1 /* Native Client support for ELF
      2    Copyright (C) 2012-2016 Free Software Foundation, Inc.
      3 
      4    This file is part of BFD, the Binary File Descriptor library.
      5 
      6    This program is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU General Public License as published by
      8    the Free Software Foundation; either version 3 of the License, or
      9    (at your option) any later version.
     10 
     11    This program is distributed in the hope that it will be useful,
     12    but WITHOUT ANY WARRANTY; without even the implied warranty of
     13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14    GNU General Public License for more details.
     15 
     16    You should have received a copy of the GNU General Public License
     17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     18 
     19 #include "sysdep.h"
     20 #include "bfd.h"
     21 #include "libbfd.h"
     22 #include "elf-bfd.h"
     23 #include "elf-nacl.h"
     24 #include "elf/common.h"
     25 #include "elf/internal.h"
     26 
     27 static bfd_boolean
     28 segment_executable (struct elf_segment_map *seg)
     29 {
     30   if (seg->p_flags_valid)
     31     return (seg->p_flags & PF_X) != 0;
     32   else
     33     {
     34       /* The p_flags value has not been computed yet,
     35 	 so we have to look through the sections.  */
     36       unsigned int i;
     37       for (i = 0; i < seg->count; ++i)
     38 	if (seg->sections[i]->flags & SEC_CODE)
     39 	  return TRUE;
     40     }
     41   return FALSE;
     42 }
     43 
     44 /* Determine if this segment is eligible to receive the file and program
     45    headers.  It must be read-only and non-executable.
     46    Its first section must start far enough past the page boundary to
     47    allow space for the headers.  */
     48 static bfd_boolean
     49 segment_eligible_for_headers (struct elf_segment_map *seg,
     50 			      bfd_vma minpagesize, bfd_vma sizeof_headers)
     51 {
     52   unsigned int i;
     53   if (seg->count == 0 || seg->sections[0]->lma % minpagesize < sizeof_headers)
     54     return FALSE;
     55   for (i = 0; i < seg->count; ++i)
     56     {
     57       if ((seg->sections[i]->flags & (SEC_CODE|SEC_READONLY)) != SEC_READONLY)
     58 	return FALSE;
     59     }
     60   return TRUE;
     61 }
     62 
     63 
     64 /* We permute the segment_map to get BFD to do the file layout we want:
     65    The first non-executable PT_LOAD segment appears first in the file
     66    and contains the ELF file header and phdrs.  */
     67 bfd_boolean
     68 nacl_modify_segment_map (bfd *abfd, struct bfd_link_info *info)
     69 {
     70   const struct elf_backend_data *const bed = get_elf_backend_data (abfd);
     71   struct elf_segment_map **m = &elf_seg_map (abfd);
     72   struct elf_segment_map **first_load = NULL;
     73   struct elf_segment_map **last_load = NULL;
     74   bfd_boolean moved_headers = FALSE;
     75   int sizeof_headers;
     76 
     77   if (info != NULL && info->user_phdrs)
     78     /* The linker script used PHDRS explicitly, so don't change what the
     79        user asked for.  */
     80     return TRUE;
     81 
     82   if (info != NULL)
     83     /* We're doing linking, so evalute SIZEOF_HEADERS as in a linker script.  */
     84     sizeof_headers = bfd_sizeof_headers (abfd, info);
     85   else
     86     {
     87       /* We're not doing linking, so this is objcopy or suchlike.
     88 	 We just need to collect the size of the existing headers.  */
     89       struct elf_segment_map *seg;
     90       sizeof_headers = bed->s->sizeof_ehdr;
     91       for (seg = *m; seg != NULL; seg = seg->next)
     92 	sizeof_headers += bed->s->sizeof_phdr;
     93     }
     94 
     95   while (*m != NULL)
     96     {
     97       struct elf_segment_map *seg = *m;
     98 
     99       if (seg->p_type == PT_LOAD)
    100 	{
    101 	  bfd_boolean executable = segment_executable (seg);
    102 
    103 	  if (executable
    104 	      && seg->count > 0
    105 	      && seg->sections[0]->vma % bed->minpagesize == 0)
    106 	    {
    107 	      asection *lastsec = seg->sections[seg->count - 1];
    108 	      bfd_vma end = lastsec->vma + lastsec->size;
    109 	      if (end % bed->minpagesize != 0)
    110 		{
    111 		  /* This is an executable segment that starts on a page
    112 		     boundary but does not end on a page boundary.  Fill
    113 		     it out to a whole page with code fill (the tail of
    114 		     the segment will not be within any section).  Thus
    115 		     the entire code segment can be mapped from the file
    116 		     as whole pages and that mapping will contain only
    117 		     valid instructions.
    118 
    119 		     To accomplish this, we must fake out the code in
    120 		     assign_file_positions_for_load_sections (elf.c) so
    121 		     that it advances past the rest of the final page,
    122 		     rather than trying to put the next (unaligned, or
    123 		     unallocated) section.  We do this by appending a
    124 		     dummy section record to this element in the segment
    125 		     map.  No such output section ever actually exists,
    126 		     but this gets the layout logic to advance the file
    127 		     positions past this partial page.  Since we are
    128 		     lying to BFD like this, nothing will ever know to
    129 		     write the section contents.  So we do that by hand
    130 		     after the fact, in nacl_final_write_processing, below.  */
    131 
    132 		  struct elf_segment_map *newseg;
    133 		  asection *sec;
    134 		  struct bfd_elf_section_data *secdata;
    135 
    136 		  BFD_ASSERT (!seg->p_size_valid);
    137 
    138 		  secdata = bfd_zalloc (abfd, sizeof *secdata);
    139 		  if (secdata == NULL)
    140 		    return FALSE;
    141 
    142 		  sec = bfd_zalloc (abfd, sizeof *sec);
    143 		  if (sec == NULL)
    144 		    return FALSE;
    145 
    146 		  /* Fill in only the fields that actually affect the logic
    147 		     in assign_file_positions_for_load_sections.  */
    148 		  sec->vma = end;
    149 		  sec->lma = lastsec->lma + lastsec->size;
    150 		  sec->size = bed->minpagesize - (end % bed->minpagesize);
    151 		  sec->flags = (SEC_ALLOC | SEC_LOAD
    152 				| SEC_READONLY | SEC_CODE | SEC_LINKER_CREATED);
    153 		  sec->used_by_bfd = secdata;
    154 
    155 		  secdata->this_hdr.sh_type = SHT_PROGBITS;
    156 		  secdata->this_hdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR;
    157 		  secdata->this_hdr.sh_addr = sec->vma;
    158 		  secdata->this_hdr.sh_size = sec->size;
    159 
    160 		  newseg = bfd_alloc (abfd,
    161 				      sizeof *newseg + ((seg->count + 1)
    162 							* sizeof (asection *)));
    163 		  if (newseg == NULL)
    164 		    return FALSE;
    165 		  memcpy (newseg, seg,
    166 			  sizeof *newseg + (seg->count * sizeof (asection *)));
    167 		  newseg->sections[newseg->count++] = sec;
    168 		  *m = seg = newseg;
    169 		}
    170 	    }
    171 
    172 	  /* First, we're just finding the earliest PT_LOAD.
    173 	     By the normal rules, this will be the lowest-addressed one.
    174 	     We only have anything interesting to do if it's executable.  */
    175 	  last_load = m;
    176 	  if (first_load == NULL)
    177 	    {
    178 	      if (!executable)
    179 		goto next;
    180 	      first_load = m;
    181 	    }
    182 	  /* Now that we've noted the first PT_LOAD, we're looking for
    183 	     the first non-executable PT_LOAD with a nonempty p_filesz.  */
    184 	  else if (!moved_headers
    185 		   && segment_eligible_for_headers (seg, bed->minpagesize,
    186 						    sizeof_headers))
    187 	    {
    188 	      /* This is the one we were looking for!
    189 
    190 		 First, clear the flags on previous segments that
    191 		 say they include the file header and phdrs.  */
    192 	      struct elf_segment_map *prevseg;
    193 	      for (prevseg = *first_load;
    194 		   prevseg != seg;
    195 		   prevseg = prevseg->next)
    196 		if (prevseg->p_type == PT_LOAD)
    197 		  {
    198 		    prevseg->includes_filehdr = 0;
    199 		    prevseg->includes_phdrs = 0;
    200 		  }
    201 
    202 	      /* This segment will include those headers instead.  */
    203 	      seg->includes_filehdr = 1;
    204 	      seg->includes_phdrs = 1;
    205 
    206 	      moved_headers = TRUE;
    207 	    }
    208 	}
    209 
    210     next:
    211       m = &seg->next;
    212     }
    213 
    214   if (first_load != last_load && moved_headers)
    215     {
    216       /* Now swap the first and last PT_LOAD segments'
    217 	 positions in segment_map.  */
    218       struct elf_segment_map *first = *first_load;
    219       struct elf_segment_map *last = *last_load;
    220       *first_load = first->next;
    221       first->next = last->next;
    222       last->next = first;
    223     }
    224 
    225   return TRUE;
    226 }
    227 
    228 /* After nacl_modify_segment_map has done its work, the file layout has
    229    been done as we wanted.  But the PT_LOAD phdrs are no longer in the
    230    proper order for the ELF rule that they must appear in ascending address
    231    order.  So find the two segments we swapped before, and swap them back.  */
    232 bfd_boolean
    233 nacl_modify_program_headers (bfd *abfd, struct bfd_link_info *info)
    234 {
    235   struct elf_segment_map **m = &elf_seg_map (abfd);
    236   Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr;
    237   Elf_Internal_Phdr *p = phdr;
    238 
    239   if (info != NULL && info->user_phdrs)
    240     /* The linker script used PHDRS explicitly, so don't change what the
    241        user asked for.  */
    242     return TRUE;
    243 
    244   /* Find the PT_LOAD that contains the headers (should be the first).  */
    245   while (*m != NULL)
    246     {
    247       if ((*m)->p_type == PT_LOAD && (*m)->includes_filehdr)
    248 	break;
    249 
    250       m = &(*m)->next;
    251       ++p;
    252     }
    253 
    254   if (*m != NULL)
    255     {
    256       struct elf_segment_map **first_load_seg = m;
    257       Elf_Internal_Phdr *first_load_phdr = p;
    258       struct elf_segment_map **next_load_seg = NULL;
    259       Elf_Internal_Phdr *next_load_phdr = NULL;
    260 
    261       /* Now move past that first one and find the PT_LOAD that should be
    262 	 before it by address order.  */
    263 
    264       m = &(*m)->next;
    265       ++p;
    266 
    267       while (*m != NULL)
    268 	{
    269 	  if (p->p_type == PT_LOAD && p->p_vaddr < first_load_phdr->p_vaddr)
    270 	    {
    271 	      next_load_seg = m;
    272 	      next_load_phdr = p;
    273 	      break;
    274 	    }
    275 
    276 	  m = &(*m)->next;
    277 	  ++p;
    278 	}
    279 
    280       /* Swap their positions in the segment_map back to how they used to be.
    281 	 The phdrs have already been set up by now, so we have to slide up
    282 	 the earlier ones to insert the one that should be first.  */
    283       if (next_load_seg != NULL)
    284 	{
    285 	  Elf_Internal_Phdr move_phdr;
    286 	  struct elf_segment_map *first_seg = *first_load_seg;
    287 	  struct elf_segment_map *next_seg = *next_load_seg;
    288 	  struct elf_segment_map *first_next = first_seg->next;
    289 	  struct elf_segment_map *next_next = next_seg->next;
    290 
    291 	  if (next_load_seg == &first_seg->next)
    292 	    {
    293 	      *first_load_seg = next_seg;
    294 	      next_seg->next = first_seg;
    295 	      first_seg->next = next_next;
    296 	    }
    297 	  else
    298 	    {
    299 	      *first_load_seg = first_next;
    300 	      *next_load_seg = next_next;
    301 
    302 	      first_seg->next = *next_load_seg;
    303 	      *next_load_seg = first_seg;
    304 
    305 	      next_seg->next = *first_load_seg;
    306 	      *first_load_seg = next_seg;
    307 	    }
    308 
    309 	  move_phdr = *next_load_phdr;
    310 	  memmove (first_load_phdr + 1, first_load_phdr,
    311 		   (next_load_phdr - first_load_phdr) * sizeof move_phdr);
    312 	  *first_load_phdr = move_phdr;
    313 	}
    314     }
    315 
    316   return TRUE;
    317 }
    318 
    319 void
    320 nacl_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
    321 {
    322   struct elf_segment_map *seg;
    323   for (seg = elf_seg_map (abfd); seg != NULL; seg = seg->next)
    324     if (seg->p_type == PT_LOAD
    325 	&& seg->count > 1
    326 	&& seg->sections[seg->count - 1]->owner == NULL)
    327       {
    328 	/* This is a fake section added in nacl_modify_segment_map, above.
    329 	   It's not a real BFD section, so nothing wrote its contents.
    330 	   Now write out its contents.  */
    331 
    332 	asection *sec = seg->sections[seg->count - 1];
    333 	char *fill;
    334 
    335 	BFD_ASSERT (sec->flags & SEC_LINKER_CREATED);
    336 	BFD_ASSERT (sec->flags & SEC_CODE);
    337 	BFD_ASSERT (sec->size > 0);
    338 
    339 	fill = abfd->arch_info->fill (sec->size, bfd_big_endian (abfd), TRUE);
    340 
    341 	if (fill == NULL
    342 	    || bfd_seek (abfd, sec->filepos, SEEK_SET) != 0
    343 	    || bfd_bwrite (fill, sec->size, abfd) != sec->size)
    344 	  {
    345 	    /* We don't have a proper way to report an error here.  So
    346 	       instead fudge things so that elf_write_shdrs_and_ehdr will
    347 	       fail.  */
    348 	    elf_elfheader (abfd)->e_shoff = (file_ptr) -1;
    349 	  }
    350 
    351 	free (fill);
    352       }
    353 }
    354