OLD | NEW |
(Empty) | |
| 1 /* Native Client support for ELF |
| 2 Copyright 2012 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 "elf-bfd.h" |
| 24 #include "elf-nacl.h" |
| 25 #include "elf/common.h" |
| 26 #include "elf/internal.h" |
| 27 |
| 28 static bfd_boolean |
| 29 segment_executable (struct elf_segment_map *seg) |
| 30 { |
| 31 if (seg->p_flags_valid) |
| 32 return (seg->p_flags & PF_X) != 0; |
| 33 else |
| 34 { |
| 35 /* The p_flags value has not been computed yet, |
| 36 so we have to look through the sections. */ |
| 37 unsigned int i; |
| 38 for (i = 0; i < seg->count; ++i) |
| 39 if (seg->sections[i]->flags & SEC_CODE) |
| 40 return TRUE; |
| 41 } |
| 42 return FALSE; |
| 43 } |
| 44 |
| 45 static bfd_boolean |
| 46 segment_nonexecutable_and_has_contents (struct elf_segment_map *seg) |
| 47 { |
| 48 bfd_boolean any_contents = FALSE; |
| 49 unsigned int i; |
| 50 for (i = 0; i < seg->count; ++i) |
| 51 { |
| 52 if (seg->sections[i]->flags & SEC_CODE) |
| 53 return FALSE; |
| 54 if (seg->sections[i]->flags & SEC_HAS_CONTENTS) |
| 55 any_contents = TRUE; |
| 56 } |
| 57 return any_contents; |
| 58 } |
| 59 |
| 60 |
| 61 /* We permute the segment_map to get BFD to do the file layout we want: |
| 62 The first non-executable PT_LOAD segment appears first in the file |
| 63 and contains the ELF file header and phdrs. */ |
| 64 bfd_boolean |
| 65 nacl_modify_segment_map (bfd *abfd, struct bfd_link_info *info) |
| 66 { |
| 67 struct elf_segment_map **m = &elf_tdata (abfd)->segment_map; |
| 68 struct elf_segment_map **first_load = NULL; |
| 69 struct elf_segment_map **last_load = NULL; |
| 70 bfd_boolean moved_headers = FALSE; |
| 71 |
| 72 if (info != NULL && info->user_phdrs) |
| 73 /* The linker script used PHDRS explicitly, so don't change what the |
| 74 user asked for. */ |
| 75 return TRUE; |
| 76 |
| 77 while (*m != NULL) |
| 78 { |
| 79 struct elf_segment_map *seg = *m; |
| 80 |
| 81 if (seg->p_type == PT_LOAD) |
| 82 { |
| 83 /* First, we're just finding the earliest PT_LOAD. |
| 84 By the normal rules, this will be the lowest-addressed one. |
| 85 We only have anything interesting to do if it's executable. */ |
| 86 last_load = m; |
| 87 if (first_load == NULL) |
| 88 { |
| 89 if (!segment_executable (*m)) |
| 90 return TRUE; |
| 91 first_load = m; |
| 92 } |
| 93 /* Now that we've noted the first PT_LOAD, we're looking for |
| 94 the first non-executable PT_LOAD with a nonempty p_filesz. */ |
| 95 else if (!moved_headers |
| 96 && segment_nonexecutable_and_has_contents (seg)) |
| 97 { |
| 98 /* This is the one we were looking for! |
| 99 |
| 100 First, clear the flags on previous segments that |
| 101 say they include the file header and phdrs. */ |
| 102 struct elf_segment_map *prevseg; |
| 103 for (prevseg = *first_load; |
| 104 prevseg != seg; |
| 105 prevseg = prevseg->next) |
| 106 if (prevseg->p_type == PT_LOAD) |
| 107 { |
| 108 prevseg->includes_filehdr = 0; |
| 109 prevseg->includes_phdrs = 0; |
| 110 } |
| 111 |
| 112 /* This segment will include those headers instead. */ |
| 113 seg->includes_filehdr = 1; |
| 114 seg->includes_phdrs = 1; |
| 115 |
| 116 moved_headers = TRUE; |
| 117 } |
| 118 } |
| 119 |
| 120 m = &seg->next; |
| 121 } |
| 122 |
| 123 if (first_load != last_load && moved_headers) |
| 124 { |
| 125 /* Now swap the first and last PT_LOAD segments' |
| 126 positions in segment_map. */ |
| 127 struct elf_segment_map *first = *first_load; |
| 128 struct elf_segment_map *last = *last_load; |
| 129 *first_load = first->next; |
| 130 first->next = last->next; |
| 131 last->next = first; |
| 132 } |
| 133 |
| 134 return TRUE; |
| 135 } |
| 136 |
| 137 /* After nacl_modify_segment_map has done its work, the file layout has |
| 138 been done as we wanted. But the PT_LOAD phdrs are no longer in the |
| 139 proper order for the ELF rule that they must appear in ascending address |
| 140 order. So find the two segments we swapped before, and swap them back. */ |
| 141 bfd_boolean |
| 142 nacl_modify_program_headers (bfd *abfd, |
| 143 struct bfd_link_info *info ATTRIBUTE_UNUSED) |
| 144 { |
| 145 struct elf_segment_map **m = &elf_tdata (abfd)->segment_map; |
| 146 Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr; |
| 147 Elf_Internal_Phdr *p = phdr; |
| 148 |
| 149 if (info != NULL && info->user_phdrs) |
| 150 /* The linker script used PHDRS explicitly, so don't change what the |
| 151 user asked for. */ |
| 152 return TRUE; |
| 153 |
| 154 /* Find the PT_LOAD that contains the headers (should be the first). */ |
| 155 while (*m != NULL) |
| 156 { |
| 157 if ((*m)->p_type == PT_LOAD && (*m)->includes_filehdr) |
| 158 break; |
| 159 |
| 160 m = &(*m)->next; |
| 161 ++p; |
| 162 } |
| 163 |
| 164 if (*m != NULL) |
| 165 { |
| 166 struct elf_segment_map **first_load_seg = m; |
| 167 Elf_Internal_Phdr *first_load_phdr = p; |
| 168 struct elf_segment_map **next_load_seg = NULL; |
| 169 Elf_Internal_Phdr *next_load_phdr = NULL; |
| 170 |
| 171 /* Now move past that first one and find the PT_LOAD that should be |
| 172 before it by address order. */ |
| 173 |
| 174 m = &(*m)->next; |
| 175 ++p; |
| 176 |
| 177 while ((*m) != NULL) |
| 178 { |
| 179 if (p->p_type == PT_LOAD && p->p_vaddr < first_load_phdr->p_vaddr) |
| 180 { |
| 181 next_load_seg = m; |
| 182 next_load_phdr = p; |
| 183 break; |
| 184 } |
| 185 |
| 186 m = &(*m)->next; |
| 187 ++p; |
| 188 } |
| 189 |
| 190 /* Swap their positions in the segment_map back to how they used to be. |
| 191 The phdrs have already been set up by now, so we have to slide up |
| 192 the earlier ones to insert the one that should be first. */ |
| 193 if (next_load_seg != NULL) |
| 194 { |
| 195 Elf_Internal_Phdr move_phdr; |
| 196 struct elf_segment_map *first_seg = *first_load_seg; |
| 197 struct elf_segment_map *next_seg = *next_load_seg; |
| 198 struct elf_segment_map *first_next = first_seg->next; |
| 199 struct elf_segment_map *next_next = next_seg->next; |
| 200 |
| 201 first_seg->next = next_next; |
| 202 *first_load_seg = next_seg; |
| 203 |
| 204 next_seg->next = first_next; |
| 205 *next_load_seg = first_seg; |
| 206 |
| 207 move_phdr = *next_load_phdr; |
| 208 memmove (first_load_phdr + 1, first_load_phdr, |
| 209 (next_load_phdr - first_load_phdr) * sizeof move_phdr); |
| 210 *first_load_phdr = move_phdr; |
| 211 } |
| 212 } |
| 213 |
| 214 return TRUE; |
| 215 } |
OLD | NEW |