(root)/
binutils-2.41/
bfd/
elf-nacl.c
       1  /* Native Client support for ELF
       2     Copyright (C) 2012-2023 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 bool
      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 bool
      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  bool
      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 **headers = NULL;
      74    int sizeof_headers;
      75  
      76    if (info != NULL && info->user_phdrs)
      77      /* The linker script used PHDRS explicitly, so don't change what the
      78         user asked for.  */
      79      return true;
      80  
      81    if (info != NULL)
      82      /* We're doing linking, so evalute SIZEOF_HEADERS as in a linker script.  */
      83      sizeof_headers = bfd_sizeof_headers (abfd, info);
      84    else
      85      {
      86        /* We're not doing linking, so this is objcopy or suchlike.
      87  	 We just need to collect the size of the existing headers.  */
      88        struct elf_segment_map *seg;
      89        sizeof_headers = bed->s->sizeof_ehdr;
      90        for (seg = *m; seg != NULL; seg = seg->next)
      91  	sizeof_headers += bed->s->sizeof_phdr;
      92      }
      93  
      94    while (*m != NULL)
      95      {
      96        struct elf_segment_map *seg = *m;
      97  
      98        if (seg->p_type == PT_LOAD)
      99  	{
     100  	  bool executable = segment_executable (seg);
     101  
     102  	  if (executable
     103  	      && seg->count > 0
     104  	      && seg->sections[0]->vma % bed->minpagesize == 0)
     105  	    {
     106  	      asection *lastsec = seg->sections[seg->count - 1];
     107  	      bfd_vma end = lastsec->vma + lastsec->size;
     108  	      if (end % bed->minpagesize != 0)
     109  		{
     110  		  /* This is an executable segment that starts on a page
     111  		     boundary but does not end on a page boundary.  Fill
     112  		     it out to a whole page with code fill (the tail of
     113  		     the segment will not be within any section).  Thus
     114  		     the entire code segment can be mapped from the file
     115  		     as whole pages and that mapping will contain only
     116  		     valid instructions.
     117  
     118  		     To accomplish this, we must fake out the code in
     119  		     assign_file_positions_for_load_sections (elf.c) so
     120  		     that it advances past the rest of the final page,
     121  		     rather than trying to put the next (unaligned, or
     122  		     unallocated) section.  We do this by appending a
     123  		     dummy section record to this element in the segment
     124  		     map.  No such output section ever actually exists,
     125  		     but this gets the layout logic to advance the file
     126  		     positions past this partial page.  Since we are
     127  		     lying to BFD like this, nothing will ever know to
     128  		     write the section contents.  So we do that by hand
     129  		     after the fact, in nacl_final_write_processing, below.  */
     130  
     131  		  struct elf_segment_map *newseg;
     132  		  asection *sec;
     133  		  struct bfd_elf_section_data *secdata;
     134  
     135  		  BFD_ASSERT (!seg->p_size_valid);
     136  
     137  		  secdata = bfd_zalloc (abfd, sizeof *secdata);
     138  		  if (secdata == NULL)
     139  		    return false;
     140  
     141  		  sec = bfd_zalloc (abfd, sizeof *sec);
     142  		  if (sec == NULL)
     143  		    return false;
     144  
     145  		  /* Fill in only the fields that actually affect the logic
     146  		     in assign_file_positions_for_load_sections.  */
     147  		  sec->vma = end;
     148  		  sec->lma = lastsec->lma + lastsec->size;
     149  		  sec->size = bed->minpagesize - (end % bed->minpagesize);
     150  		  sec->flags = (SEC_ALLOC | SEC_LOAD
     151  				| SEC_READONLY | SEC_CODE | SEC_LINKER_CREATED);
     152  		  sec->used_by_bfd = secdata;
     153  
     154  		  secdata->this_hdr.sh_type = SHT_PROGBITS;
     155  		  secdata->this_hdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR;
     156  		  secdata->this_hdr.sh_addr = sec->vma;
     157  		  secdata->this_hdr.sh_size = sec->size;
     158  
     159  		  newseg
     160  		    = bfd_alloc (abfd, (sizeof (*newseg)
     161  					+ seg->count * sizeof (asection *)));
     162  		  if (newseg == NULL)
     163  		    return false;
     164  		  memcpy (newseg, seg, (sizeof (*newseg) - sizeof (asection *)
     165  					+ seg->count * sizeof (asection *)));
     166  		  newseg->sections[newseg->count++] = sec;
     167  		  *m = seg = newseg;
     168  		}
     169  	    }
     170  
     171  	  /* First, we're just finding the earliest PT_LOAD.
     172  	     By the normal rules, this will be the lowest-addressed one.  */
     173  	  if (first_load == NULL)
     174  	    first_load = m;
     175  
     176  	  /* Now that we've noted the first PT_LOAD, we're looking for
     177  	     the first non-executable PT_LOAD with a nonempty p_filesz.  */
     178  	  else if (headers == NULL
     179  		   && segment_eligible_for_headers (seg, bed->minpagesize,
     180  						    sizeof_headers))
     181  	    headers = m;
     182  	}
     183        m = &seg->next;
     184      }
     185  
     186    if (headers != NULL)
     187      {
     188        struct elf_segment_map **last_load = NULL;
     189        struct elf_segment_map *seg;
     190  
     191        m = first_load;
     192        while ((seg = *m) != NULL)
     193  	{
     194  	  if (seg->p_type == PT_LOAD)
     195  	    {
     196  	      /* Clear the flags on any previous segment that
     197  		 included the file header and phdrs.  */
     198  	      seg->includes_filehdr = 0;
     199  	      seg->includes_phdrs = 0;
     200  	      seg->no_sort_lma = 1;
     201  	      /* Also strip out empty segments.  */
     202  	      if (seg->count == 0)
     203  		{
     204  		  if (headers == &seg->next)
     205  		    headers = m;
     206  		  *m = seg->next;
     207  		  continue;
     208  		}
     209  	      last_load = m;
     210  	    }
     211  	  m = &seg->next;
     212  	}
     213  
     214        /* This segment will include those headers instead.  */
     215        seg = *headers;
     216        seg->includes_filehdr = 1;
     217        seg->includes_phdrs = 1;
     218  
     219        if (last_load != NULL && first_load != last_load && first_load != headers)
     220  	{
     221  	  /* Put the first PT_LOAD header last.  */
     222  	  struct elf_segment_map *first = *first_load;
     223  	  struct elf_segment_map *last = *last_load;
     224  	  *first_load = first->next;
     225  	  first->next = last->next;
     226  	  last->next = first;
     227  	}
     228      }
     229  
     230    return true;
     231  }
     232  
     233  /* After nacl_modify_segment_map has done its work, the file layout has
     234     been done as we wanted.  But the PT_LOAD phdrs are no longer in the
     235     proper order for the ELF rule that they must appear in ascending address
     236     order.  So find the two segments we swapped before, and swap them back.  */
     237  bool
     238  nacl_modify_headers (bfd *abfd, struct bfd_link_info *info)
     239  {
     240    if (info != NULL && info->user_phdrs)
     241      /* The linker script used PHDRS explicitly, so don't change what the
     242         user asked for.  */
     243      ;
     244    else
     245      {
     246        struct elf_segment_map **m = &elf_seg_map (abfd);
     247        Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr;
     248        Elf_Internal_Phdr *p = phdr;
     249  
     250        /* Find the PT_LOAD that contains the headers (should be the first).  */
     251        while (*m != NULL)
     252  	{
     253  	  if ((*m)->p_type == PT_LOAD && (*m)->includes_filehdr)
     254  	    break;
     255  
     256  	  m = &(*m)->next;
     257  	  ++p;
     258  	}
     259  
     260        if (*m != NULL)
     261  	{
     262  	  struct elf_segment_map **first_load_seg = m;
     263  	  Elf_Internal_Phdr *first_load_phdr = p;
     264  	  struct elf_segment_map **next_load_seg = NULL;
     265  	  Elf_Internal_Phdr *next_load_phdr = NULL;
     266  
     267  	  /* Now move past that first one and find the PT_LOAD that should be
     268  	     before it by address order.  */
     269  
     270  	  m = &(*m)->next;
     271  	  ++p;
     272  
     273  	  while (*m != NULL)
     274  	    {
     275  	      if (p->p_type == PT_LOAD && p->p_vaddr < first_load_phdr->p_vaddr)
     276  		{
     277  		  next_load_seg = m;
     278  		  next_load_phdr = p;
     279  		  break;
     280  		}
     281  
     282  	      m = &(*m)->next;
     283  	      ++p;
     284  	    }
     285  
     286  	  /* Swap their positions in the segment_map back to how they
     287  	     used to be.  The phdrs have already been set up by now,
     288  	     so we have to slide up the earlier ones to insert the one
     289  	     that should be first.  */
     290  	  if (next_load_seg != NULL)
     291  	    {
     292  	      Elf_Internal_Phdr move_phdr;
     293  	      struct elf_segment_map *first_seg = *first_load_seg;
     294  	      struct elf_segment_map *next_seg = *next_load_seg;
     295  	      struct elf_segment_map *first_next = first_seg->next;
     296  	      struct elf_segment_map *next_next = next_seg->next;
     297  
     298  	      if (next_load_seg == &first_seg->next)
     299  		{
     300  		  *first_load_seg = next_seg;
     301  		  next_seg->next = first_seg;
     302  		  first_seg->next = next_next;
     303  		}
     304  	      else
     305  		{
     306  		  *first_load_seg = first_next;
     307  		  *next_load_seg = next_next;
     308  
     309  		  first_seg->next = *next_load_seg;
     310  		  *next_load_seg = first_seg;
     311  
     312  		  next_seg->next = *first_load_seg;
     313  		  *first_load_seg = next_seg;
     314  		}
     315  
     316  	      move_phdr = *next_load_phdr;
     317  	      memmove (first_load_phdr + 1, first_load_phdr,
     318  		       (next_load_phdr - first_load_phdr) * sizeof move_phdr);
     319  	      *first_load_phdr = move_phdr;
     320  	    }
     321  	}
     322      }
     323  
     324    return _bfd_elf_modify_headers (abfd, info);
     325  }
     326  
     327  bool
     328  nacl_final_write_processing (bfd *abfd)
     329  {
     330    struct elf_segment_map *seg;
     331    for (seg = elf_seg_map (abfd); seg != NULL; seg = seg->next)
     332      if (seg->p_type == PT_LOAD
     333  	&& seg->count > 1
     334  	&& seg->sections[seg->count - 1]->owner == NULL)
     335        {
     336  	/* This is a fake section added in nacl_modify_segment_map, above.
     337  	   It's not a real BFD section, so nothing wrote its contents.
     338  	   Now write out its contents.  */
     339  
     340  	asection *sec = seg->sections[seg->count - 1];
     341  	char *fill;
     342  
     343  	BFD_ASSERT (sec->flags & SEC_LINKER_CREATED);
     344  	BFD_ASSERT (sec->flags & SEC_CODE);
     345  	BFD_ASSERT (sec->size > 0);
     346  
     347  	fill = abfd->arch_info->fill (sec->size, bfd_big_endian (abfd), true);
     348  
     349  	if (fill == NULL
     350  	    || bfd_seek (abfd, sec->filepos, SEEK_SET) != 0
     351  	    || bfd_bwrite (fill, sec->size, abfd) != sec->size)
     352  	  {
     353  	    /* We don't have a proper way to report an error here.  So
     354  	       instead fudge things so that elf_write_shdrs_and_ehdr will
     355  	       fail.  */
     356  	    elf_elfheader (abfd)->e_shoff = (file_ptr) -1;
     357  	  }
     358  
     359  	free (fill);
     360        }
     361    return _bfd_elf_final_write_processing (abfd);
     362  }