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