xref: /dflybsd-src/contrib/gdb-7/bfd/elf-nacl.c (revision de8e141f24382815c10a4012d209bbbf7abf1112)
1*ef5ccd6cSJohn Marino /* Native Client support for ELF
2*ef5ccd6cSJohn Marino    Copyright 2012 Free Software Foundation, Inc.
3*ef5ccd6cSJohn Marino 
4*ef5ccd6cSJohn Marino    This file is part of BFD, the Binary File Descriptor library.
5*ef5ccd6cSJohn Marino 
6*ef5ccd6cSJohn Marino    This program is free software; you can redistribute it and/or modify
7*ef5ccd6cSJohn Marino    it under the terms of the GNU General Public License as published by
8*ef5ccd6cSJohn Marino    the Free Software Foundation; either version 3 of the License, or
9*ef5ccd6cSJohn Marino    (at your option) any later version.
10*ef5ccd6cSJohn Marino 
11*ef5ccd6cSJohn Marino    This program is distributed in the hope that it will be useful,
12*ef5ccd6cSJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
13*ef5ccd6cSJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*ef5ccd6cSJohn Marino    GNU General Public License for more details.
15*ef5ccd6cSJohn Marino 
16*ef5ccd6cSJohn Marino    You should have received a copy of the GNU General Public License
17*ef5ccd6cSJohn Marino    along with this program; if not, write to the Free Software
18*ef5ccd6cSJohn Marino    Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19*ef5ccd6cSJohn Marino    MA 02111-1307, USA.  */
20*ef5ccd6cSJohn Marino 
21*ef5ccd6cSJohn Marino #include "sysdep.h"
22*ef5ccd6cSJohn Marino #include "bfd.h"
23*ef5ccd6cSJohn Marino #include "elf-bfd.h"
24*ef5ccd6cSJohn Marino #include "elf-nacl.h"
25*ef5ccd6cSJohn Marino #include "elf/common.h"
26*ef5ccd6cSJohn Marino #include "elf/internal.h"
27*ef5ccd6cSJohn Marino 
28*ef5ccd6cSJohn Marino static bfd_boolean
segment_executable(struct elf_segment_map * seg)29*ef5ccd6cSJohn Marino segment_executable (struct elf_segment_map *seg)
30*ef5ccd6cSJohn Marino {
31*ef5ccd6cSJohn Marino   if (seg->p_flags_valid)
32*ef5ccd6cSJohn Marino     return (seg->p_flags & PF_X) != 0;
33*ef5ccd6cSJohn Marino   else
34*ef5ccd6cSJohn Marino     {
35*ef5ccd6cSJohn Marino       /* The p_flags value has not been computed yet,
36*ef5ccd6cSJohn Marino          so we have to look through the sections.  */
37*ef5ccd6cSJohn Marino       unsigned int i;
38*ef5ccd6cSJohn Marino       for (i = 0; i < seg->count; ++i)
39*ef5ccd6cSJohn Marino         if (seg->sections[i]->flags & SEC_CODE)
40*ef5ccd6cSJohn Marino           return TRUE;
41*ef5ccd6cSJohn Marino     }
42*ef5ccd6cSJohn Marino   return FALSE;
43*ef5ccd6cSJohn Marino }
44*ef5ccd6cSJohn Marino 
45*ef5ccd6cSJohn Marino /* Determine if this segment is eligible to receive the file and program
46*ef5ccd6cSJohn Marino    headers.  It must be read-only, non-executable, and have contents.
47*ef5ccd6cSJohn Marino    Its first section must start far enough past the page boundary to
48*ef5ccd6cSJohn Marino    allow space for the headers.  */
49*ef5ccd6cSJohn Marino static bfd_boolean
segment_eligible_for_headers(struct elf_segment_map * seg,bfd_vma maxpagesize,bfd_vma sizeof_headers)50*ef5ccd6cSJohn Marino segment_eligible_for_headers (struct elf_segment_map *seg,
51*ef5ccd6cSJohn Marino                               bfd_vma maxpagesize, bfd_vma sizeof_headers)
52*ef5ccd6cSJohn Marino {
53*ef5ccd6cSJohn Marino   bfd_boolean any_contents = FALSE;
54*ef5ccd6cSJohn Marino   unsigned int i;
55*ef5ccd6cSJohn Marino   if (seg->count == 0 || seg->sections[0]->lma % maxpagesize < sizeof_headers)
56*ef5ccd6cSJohn Marino     return FALSE;
57*ef5ccd6cSJohn Marino   for (i = 0; i < seg->count; ++i)
58*ef5ccd6cSJohn Marino     {
59*ef5ccd6cSJohn Marino       if ((seg->sections[i]->flags & (SEC_CODE|SEC_READONLY)) != SEC_READONLY)
60*ef5ccd6cSJohn Marino         return FALSE;
61*ef5ccd6cSJohn Marino       if (seg->sections[i]->flags & SEC_HAS_CONTENTS)
62*ef5ccd6cSJohn Marino         any_contents = TRUE;
63*ef5ccd6cSJohn Marino     }
64*ef5ccd6cSJohn Marino   return any_contents;
65*ef5ccd6cSJohn Marino }
66*ef5ccd6cSJohn Marino 
67*ef5ccd6cSJohn Marino 
68*ef5ccd6cSJohn Marino /* We permute the segment_map to get BFD to do the file layout we want:
69*ef5ccd6cSJohn Marino    The first non-executable PT_LOAD segment appears first in the file
70*ef5ccd6cSJohn Marino    and contains the ELF file header and phdrs.  */
71*ef5ccd6cSJohn Marino bfd_boolean
nacl_modify_segment_map(bfd * abfd,struct bfd_link_info * info)72*ef5ccd6cSJohn Marino nacl_modify_segment_map (bfd *abfd, struct bfd_link_info *info)
73*ef5ccd6cSJohn Marino {
74*ef5ccd6cSJohn Marino   struct elf_segment_map **m = &elf_seg_map (abfd);
75*ef5ccd6cSJohn Marino   struct elf_segment_map **first_load = NULL;
76*ef5ccd6cSJohn Marino   struct elf_segment_map **last_load = NULL;
77*ef5ccd6cSJohn Marino   bfd_boolean moved_headers = FALSE;
78*ef5ccd6cSJohn Marino   int sizeof_headers = info == NULL ? 0 : bfd_sizeof_headers (abfd, info);
79*ef5ccd6cSJohn Marino   bfd_vma maxpagesize = get_elf_backend_data (abfd)->maxpagesize;
80*ef5ccd6cSJohn Marino 
81*ef5ccd6cSJohn Marino   if (info != NULL && info->user_phdrs)
82*ef5ccd6cSJohn Marino     /* The linker script used PHDRS explicitly, so don't change what the
83*ef5ccd6cSJohn Marino        user asked for.  */
84*ef5ccd6cSJohn Marino     return TRUE;
85*ef5ccd6cSJohn Marino 
86*ef5ccd6cSJohn Marino   while (*m != NULL)
87*ef5ccd6cSJohn Marino     {
88*ef5ccd6cSJohn Marino       struct elf_segment_map *seg = *m;
89*ef5ccd6cSJohn Marino 
90*ef5ccd6cSJohn Marino       if (seg->p_type == PT_LOAD)
91*ef5ccd6cSJohn Marino         {
92*ef5ccd6cSJohn Marino           /* First, we're just finding the earliest PT_LOAD.
93*ef5ccd6cSJohn Marino              By the normal rules, this will be the lowest-addressed one.
94*ef5ccd6cSJohn Marino              We only have anything interesting to do if it's executable.  */
95*ef5ccd6cSJohn Marino           last_load = m;
96*ef5ccd6cSJohn Marino           if (first_load == NULL)
97*ef5ccd6cSJohn Marino             {
98*ef5ccd6cSJohn Marino               if (!segment_executable (*m))
99*ef5ccd6cSJohn Marino                 return TRUE;
100*ef5ccd6cSJohn Marino               first_load = m;
101*ef5ccd6cSJohn Marino             }
102*ef5ccd6cSJohn Marino           /* Now that we've noted the first PT_LOAD, we're looking for
103*ef5ccd6cSJohn Marino              the first non-executable PT_LOAD with a nonempty p_filesz.  */
104*ef5ccd6cSJohn Marino           else if (!moved_headers
105*ef5ccd6cSJohn Marino                    && segment_eligible_for_headers (seg, maxpagesize,
106*ef5ccd6cSJohn Marino                                                     sizeof_headers))
107*ef5ccd6cSJohn Marino             {
108*ef5ccd6cSJohn Marino               /* This is the one we were looking for!
109*ef5ccd6cSJohn Marino 
110*ef5ccd6cSJohn Marino                  First, clear the flags on previous segments that
111*ef5ccd6cSJohn Marino                  say they include the file header and phdrs.  */
112*ef5ccd6cSJohn Marino               struct elf_segment_map *prevseg;
113*ef5ccd6cSJohn Marino               for (prevseg = *first_load;
114*ef5ccd6cSJohn Marino                    prevseg != seg;
115*ef5ccd6cSJohn Marino                    prevseg = prevseg->next)
116*ef5ccd6cSJohn Marino                 if (prevseg->p_type == PT_LOAD)
117*ef5ccd6cSJohn Marino                   {
118*ef5ccd6cSJohn Marino                     prevseg->includes_filehdr = 0;
119*ef5ccd6cSJohn Marino                     prevseg->includes_phdrs = 0;
120*ef5ccd6cSJohn Marino                   }
121*ef5ccd6cSJohn Marino 
122*ef5ccd6cSJohn Marino               /* This segment will include those headers instead.  */
123*ef5ccd6cSJohn Marino               seg->includes_filehdr = 1;
124*ef5ccd6cSJohn Marino               seg->includes_phdrs = 1;
125*ef5ccd6cSJohn Marino 
126*ef5ccd6cSJohn Marino               moved_headers = TRUE;
127*ef5ccd6cSJohn Marino             }
128*ef5ccd6cSJohn Marino         }
129*ef5ccd6cSJohn Marino 
130*ef5ccd6cSJohn Marino       m = &seg->next;
131*ef5ccd6cSJohn Marino     }
132*ef5ccd6cSJohn Marino 
133*ef5ccd6cSJohn Marino   if (first_load != last_load && moved_headers)
134*ef5ccd6cSJohn Marino     {
135*ef5ccd6cSJohn Marino       /* Now swap the first and last PT_LOAD segments'
136*ef5ccd6cSJohn Marino          positions in segment_map.  */
137*ef5ccd6cSJohn Marino       struct elf_segment_map *first = *first_load;
138*ef5ccd6cSJohn Marino       struct elf_segment_map *last = *last_load;
139*ef5ccd6cSJohn Marino       *first_load = first->next;
140*ef5ccd6cSJohn Marino       first->next = last->next;
141*ef5ccd6cSJohn Marino       last->next = first;
142*ef5ccd6cSJohn Marino     }
143*ef5ccd6cSJohn Marino 
144*ef5ccd6cSJohn Marino   return TRUE;
145*ef5ccd6cSJohn Marino }
146*ef5ccd6cSJohn Marino 
147*ef5ccd6cSJohn Marino /* After nacl_modify_segment_map has done its work, the file layout has
148*ef5ccd6cSJohn Marino    been done as we wanted.  But the PT_LOAD phdrs are no longer in the
149*ef5ccd6cSJohn Marino    proper order for the ELF rule that they must appear in ascending address
150*ef5ccd6cSJohn Marino    order.  So find the two segments we swapped before, and swap them back.  */
151*ef5ccd6cSJohn Marino bfd_boolean
nacl_modify_program_headers(bfd * abfd,struct bfd_link_info * info)152*ef5ccd6cSJohn Marino nacl_modify_program_headers (bfd *abfd, struct bfd_link_info *info)
153*ef5ccd6cSJohn Marino {
154*ef5ccd6cSJohn Marino   struct elf_segment_map **m = &elf_seg_map (abfd);
155*ef5ccd6cSJohn Marino   Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr;
156*ef5ccd6cSJohn Marino   Elf_Internal_Phdr *p = phdr;
157*ef5ccd6cSJohn Marino 
158*ef5ccd6cSJohn Marino   if (info != NULL && info->user_phdrs)
159*ef5ccd6cSJohn Marino     /* The linker script used PHDRS explicitly, so don't change what the
160*ef5ccd6cSJohn Marino        user asked for.  */
161*ef5ccd6cSJohn Marino     return TRUE;
162*ef5ccd6cSJohn Marino 
163*ef5ccd6cSJohn Marino   /* Find the PT_LOAD that contains the headers (should be the first).  */
164*ef5ccd6cSJohn Marino   while (*m != NULL)
165*ef5ccd6cSJohn Marino     {
166*ef5ccd6cSJohn Marino       if ((*m)->p_type == PT_LOAD && (*m)->includes_filehdr)
167*ef5ccd6cSJohn Marino         break;
168*ef5ccd6cSJohn Marino 
169*ef5ccd6cSJohn Marino       m = &(*m)->next;
170*ef5ccd6cSJohn Marino       ++p;
171*ef5ccd6cSJohn Marino     }
172*ef5ccd6cSJohn Marino 
173*ef5ccd6cSJohn Marino   if (*m != NULL)
174*ef5ccd6cSJohn Marino     {
175*ef5ccd6cSJohn Marino       struct elf_segment_map **first_load_seg = m;
176*ef5ccd6cSJohn Marino       Elf_Internal_Phdr *first_load_phdr = p;
177*ef5ccd6cSJohn Marino       struct elf_segment_map **next_load_seg = NULL;
178*ef5ccd6cSJohn Marino       Elf_Internal_Phdr *next_load_phdr = NULL;
179*ef5ccd6cSJohn Marino 
180*ef5ccd6cSJohn Marino       /* Now move past that first one and find the PT_LOAD that should be
181*ef5ccd6cSJohn Marino          before it by address order.  */
182*ef5ccd6cSJohn Marino 
183*ef5ccd6cSJohn Marino       m = &(*m)->next;
184*ef5ccd6cSJohn Marino       ++p;
185*ef5ccd6cSJohn Marino 
186*ef5ccd6cSJohn Marino       while ((*m) != NULL)
187*ef5ccd6cSJohn Marino         {
188*ef5ccd6cSJohn Marino           if (p->p_type == PT_LOAD && p->p_vaddr < first_load_phdr->p_vaddr)
189*ef5ccd6cSJohn Marino             {
190*ef5ccd6cSJohn Marino               next_load_seg = m;
191*ef5ccd6cSJohn Marino               next_load_phdr = p;
192*ef5ccd6cSJohn Marino               break;
193*ef5ccd6cSJohn Marino             }
194*ef5ccd6cSJohn Marino 
195*ef5ccd6cSJohn Marino           m = &(*m)->next;
196*ef5ccd6cSJohn Marino           ++p;
197*ef5ccd6cSJohn Marino         }
198*ef5ccd6cSJohn Marino 
199*ef5ccd6cSJohn Marino       /* Swap their positions in the segment_map back to how they used to be.
200*ef5ccd6cSJohn Marino          The phdrs have already been set up by now, so we have to slide up
201*ef5ccd6cSJohn Marino          the earlier ones to insert the one that should be first.  */
202*ef5ccd6cSJohn Marino       if (next_load_seg != NULL)
203*ef5ccd6cSJohn Marino         {
204*ef5ccd6cSJohn Marino           Elf_Internal_Phdr move_phdr;
205*ef5ccd6cSJohn Marino           struct elf_segment_map *first_seg = *first_load_seg;
206*ef5ccd6cSJohn Marino           struct elf_segment_map *next_seg = *next_load_seg;
207*ef5ccd6cSJohn Marino           struct elf_segment_map *first_next = first_seg->next;
208*ef5ccd6cSJohn Marino           struct elf_segment_map *next_next = next_seg->next;
209*ef5ccd6cSJohn Marino 
210*ef5ccd6cSJohn Marino           first_seg->next = next_next;
211*ef5ccd6cSJohn Marino           *first_load_seg = next_seg;
212*ef5ccd6cSJohn Marino 
213*ef5ccd6cSJohn Marino           next_seg->next = first_next;
214*ef5ccd6cSJohn Marino           *next_load_seg = first_seg;
215*ef5ccd6cSJohn Marino 
216*ef5ccd6cSJohn Marino           move_phdr = *next_load_phdr;
217*ef5ccd6cSJohn Marino           memmove (first_load_phdr + 1, first_load_phdr,
218*ef5ccd6cSJohn Marino                    (next_load_phdr - first_load_phdr) * sizeof move_phdr);
219*ef5ccd6cSJohn Marino           *first_load_phdr = move_phdr;
220*ef5ccd6cSJohn Marino         }
221*ef5ccd6cSJohn Marino     }
222*ef5ccd6cSJohn Marino 
223*ef5ccd6cSJohn Marino   return TRUE;
224*ef5ccd6cSJohn Marino }
225