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