OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 /* | 7 /* |
8 * ncfileutil.c - open an executable file. FOR TESTING ONLY. | 8 * ncfileutil.c - open an executable file. FOR TESTING ONLY. |
9 */ | 9 */ |
10 | 10 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 if (c == ELFCLASS32) { | 76 if (c == ELFCLASS32) { |
77 return "(32 bit executable)"; | 77 return "(32 bit executable)"; |
78 } else if (c == ELFCLASS64) { | 78 } else if (c == ELFCLASS64) { |
79 return "(64 bit executable)"; | 79 return "(64 bit executable)"; |
80 } else { | 80 } else { |
81 return "(invalid class)"; | 81 return "(invalid class)"; |
82 } | 82 } |
83 } | 83 } |
84 | 84 |
85 static int nc_load(ncfile *ncf, int fd) { | 85 static int nc_load(ncfile *ncf, int fd) { |
86 | 86 union { |
87 Elf_Ehdr h; | 87 Elf32_Ehdr h32; |
| 88 #if NACL_TARGET_SUBARCH == 64 |
| 89 Elf64_Ehdr h64; |
| 90 #endif |
| 91 } h; |
| 92 Elf_Half phnum; |
| 93 Elf_Half shnum; |
| 94 Elf_Off phoff; |
| 95 Elf_Off shoff; |
88 ssize_t nread; | 96 ssize_t nread; |
89 Elf_Addr vmemlo, vmemhi; | 97 Elf_Addr vmemlo, vmemhi; |
90 size_t shsize, phsize; | 98 size_t shsize, phsize; |
91 int i; | 99 int i; |
92 | 100 |
93 /* Read and check the ELF header */ | 101 /* Read and check the ELF header */ |
94 nread = readat(ncf, fd, &h, sizeof(h), 0); | 102 nread = readat(ncf, fd, &h, sizeof(h), 0); |
95 if (nread < 0 || (size_t) nread < sizeof(h)) { | 103 if (nread < 0 || (size_t) nread < sizeof(h)) { |
96 ncf->error_fn("nc_load(%s): could not read ELF header", ncf->fname); | 104 ncf->error_fn("nc_load(%s): could not read ELF header", ncf->fname); |
97 return -1; | 105 return -1; |
98 } | 106 } |
99 | 107 |
100 /* do a bunch of sanity checks */ | 108 /* do a bunch of sanity checks */ |
101 if (strncmp((char *)h.e_ident, ELFMAG, strlen(ELFMAG))) { | 109 if (memcmp(h.h32.e_ident, ELFMAG, SELFMAG)) { |
102 ncf->error_fn("nc_load(%s): bad magic number", ncf->fname); | 110 ncf->error_fn("nc_load(%s): bad magic number", ncf->fname); |
103 return -1; | 111 return -1; |
104 } | 112 } |
105 | 113 |
106 if (h.e_ident[EI_CLASS] != NACL_ELF_CLASS) { | 114 #if NACL_TARGET_SUBARCH == 64 |
107 ncf->error_fn("nc_load(%s): bad EI CLASS %d %s\n", ncf->fname, | 115 if (h.h32.e_ident[EI_CLASS] == ELFCLASS64) { |
108 h.e_ident[EI_CLASS], GetEiClassName(h.e_ident[EI_CLASS])); | 116 if (h.h64.e_phoff > 0xffffffffU) { |
| 117 ncf->error_fn("nc_load(%s): e_phoff overflows 32 bits\n", ncf->fname); |
| 118 return -1; |
| 119 } |
| 120 if (h.h64.e_shoff > 0xffffffffU) { |
| 121 ncf->error_fn("nc_load(%s): e_shoff overflows 32 bits\n", ncf->fname); |
| 122 return -1; |
| 123 } |
| 124 phoff = (Elf32_Off) h.h64.e_phoff; |
| 125 shoff = (Elf32_Off) h.h64.e_shoff; |
| 126 phnum = h.h64.e_phnum; |
| 127 shnum = h.h64.e_shnum; |
| 128 } else |
| 129 #endif |
| 130 { |
| 131 if (h.h32.e_ident[EI_CLASS] == ELFCLASS32) { |
| 132 phoff = h.h32.e_phoff; |
| 133 shoff = h.h32.e_shoff; |
| 134 phnum = h.h32.e_phnum; |
| 135 shnum = h.h32.e_shnum; |
| 136 } else { |
| 137 ncf->error_fn("nc_load(%s): bad EI CLASS %d %s\n", ncf->fname, |
| 138 h.h32.e_ident[EI_CLASS], |
| 139 GetEiClassName(h.h32.e_ident[EI_CLASS])); |
| 140 return -1; |
| 141 } |
109 } | 142 } |
110 | 143 |
111 /* We now support only 32-byte bundle alignment. */ | 144 /* We now support only 32-byte bundle alignment. */ |
112 ncf->ncalign = 32; | 145 ncf->ncalign = 32; |
113 | 146 |
114 /* Read the program header table */ | 147 /* Read the program header table */ |
115 if (h.e_phnum <= 0 || h.e_phnum > kMaxPhnum) { | 148 if (phnum <= 0 || phnum > kMaxPhnum) { |
116 ncf->error_fn("nc_load(%s): h.e_phnum %d > kMaxPhnum %d\n", | 149 ncf->error_fn("nc_load(%s): e_phnum %d > kMaxPhnum %d\n", |
117 ncf->fname, h.e_phnum, kMaxPhnum); | 150 ncf->fname, phnum, kMaxPhnum); |
118 return -1; | 151 return -1; |
119 } | 152 } |
120 ncf->phnum = h.e_phnum; | 153 ncf->phnum = phnum; |
121 ncf->pheaders = (Elf_Phdr *)calloc(h.e_phnum, sizeof(Elf_Phdr)); | 154 ncf->pheaders = (Elf_Phdr *)calloc(phnum, sizeof(Elf_Phdr)); |
122 if (NULL == ncf->pheaders) { | 155 if (NULL == ncf->pheaders) { |
123 ncf->error_fn("nc_load(%s): calloc(%d, %"NACL_PRIdS") failed\n", | 156 ncf->error_fn("nc_load(%s): calloc(%d, %"NACL_PRIdS") failed\n", |
124 ncf->fname, h.e_phnum, sizeof(Elf_Phdr)); | 157 ncf->fname, phnum, sizeof(Elf_Phdr)); |
125 return -1; | 158 return -1; |
126 } | 159 } |
127 phsize = h.e_phnum * sizeof(*ncf->pheaders); | 160 phsize = phnum * sizeof(*ncf->pheaders); |
128 /* TODO(karl) Remove the cast to size_t, or verify size. */ | 161 #if NACL_TARGET_SUBARCH == 64 |
129 nread = readat(ncf, fd, ncf->pheaders, (off_t) phsize, (off_t) h.e_phoff); | 162 if (h.h32.e_ident[EI_CLASS] == ELFCLASS64) { |
130 if (nread < 0 || (size_t) nread < phsize) return -1; | 163 /* |
| 164 * Read 64-bit program headers and convert them. |
| 165 */ |
| 166 Elf64_Phdr phdr64[kMaxPhnum]; |
| 167 nread = readat(ncf, fd, phdr64, (off_t) (phnum * sizeof(phdr64[0])), |
| 168 (off_t) phoff); |
| 169 if (nread < 0 || (size_t) nread < phsize) return -1; |
| 170 for (i = 0; i < phnum; ++i) { |
| 171 if (phdr64[i].p_offset > 0xffffffffU || |
| 172 phdr64[i].p_vaddr > 0xffffffffU || |
| 173 phdr64[i].p_paddr > 0xffffffffU || |
| 174 phdr64[i].p_filesz > 0xffffffffU || |
| 175 phdr64[i].p_memsz > 0xffffffffU || |
| 176 phdr64[i].p_align > 0xffffffffU) { |
| 177 ncf->error_fn("nc_load(%s): phdr[%d] fields overflow 32 bits\n", |
| 178 ncf->fname, i); |
| 179 return -1; |
| 180 } |
| 181 ncf->pheaders[i].p_type = phdr64[i].p_type; |
| 182 ncf->pheaders[i].p_flags = phdr64[i].p_flags; |
| 183 ncf->pheaders[i].p_offset = (Elf32_Off) phdr64[i].p_offset; |
| 184 ncf->pheaders[i].p_vaddr = (Elf32_Addr) phdr64[i].p_vaddr; |
| 185 ncf->pheaders[i].p_paddr = (Elf32_Addr) phdr64[i].p_paddr; |
| 186 ncf->pheaders[i].p_filesz = (Elf32_Word) phdr64[i].p_filesz; |
| 187 ncf->pheaders[i].p_memsz = (Elf32_Word) phdr64[i].p_memsz; |
| 188 ncf->pheaders[i].p_align = (Elf32_Word) phdr64[i].p_align; |
| 189 } |
| 190 } else |
| 191 #endif |
| 192 { |
| 193 /* TODO(karl) Remove the cast to size_t, or verify size. */ |
| 194 nread = readat(ncf, fd, ncf->pheaders, (off_t) phsize, (off_t) phoff); |
| 195 if (nread < 0 || (size_t) nread < phsize) return -1; |
| 196 } |
131 | 197 |
132 /* Iterate through the program headers to find the virtual */ | 198 /* Iterate through the program headers to find the virtual */ |
133 /* size of loaded text. */ | 199 /* size of loaded text. */ |
134 vmemlo = MAX_ELF_ADDR; | 200 vmemlo = MAX_ELF_ADDR; |
135 vmemhi = MIN_ELF_ADDR; | 201 vmemhi = MIN_ELF_ADDR; |
136 for (i = 0; i < h.e_phnum; i++) { | 202 for (i = 0; i < phnum; i++) { |
137 if (ncf->pheaders[i].p_type != PT_LOAD) continue; | 203 if (ncf->pheaders[i].p_type != PT_LOAD) continue; |
138 if (0 == (ncf->pheaders[i].p_flags & PF_X)) continue; | 204 if (0 == (ncf->pheaders[i].p_flags & PF_X)) continue; |
139 /* This is executable text. Check low and high addrs */ | 205 /* This is executable text. Check low and high addrs */ |
140 if (vmemlo > ncf->pheaders[i].p_vaddr) vmemlo = ncf->pheaders[i].p_vaddr; | 206 if (vmemlo > ncf->pheaders[i].p_vaddr) vmemlo = ncf->pheaders[i].p_vaddr; |
141 if (vmemhi < ncf->pheaders[i].p_vaddr + ncf->pheaders[i].p_memsz) { | 207 if (vmemhi < ncf->pheaders[i].p_vaddr + ncf->pheaders[i].p_memsz) { |
142 vmemhi = ncf->pheaders[i].p_vaddr + ncf->pheaders[i].p_memsz; | 208 vmemhi = ncf->pheaders[i].p_vaddr + ncf->pheaders[i].p_memsz; |
143 } | 209 } |
144 } | 210 } |
145 ncf->size = vmemhi - vmemlo; | 211 ncf->size = vmemhi - vmemlo; |
146 ncf->vbase = vmemlo; | 212 ncf->vbase = vmemlo; |
147 /* TODO(karl) Remove the cast to size_t, or verify size. */ | 213 /* TODO(karl) Remove the cast to size_t, or verify size. */ |
148 ncf->data = (uint8_t *)calloc(1, (size_t) ncf->size); | 214 ncf->data = (uint8_t *)calloc(1, (size_t) ncf->size); |
149 if (NULL == ncf->data) { | 215 if (NULL == ncf->data) { |
150 ncf->error_fn("nc_load(%s): calloc(1, %d) failed\n", | 216 ncf->error_fn("nc_load(%s): calloc(1, %d) failed\n", |
151 ncf->fname, (int)ncf->size); | 217 ncf->fname, (int)ncf->size); |
152 return -1; | 218 return -1; |
153 } | 219 } |
154 | 220 |
155 /* Load program text segments */ | 221 /* Load program text segments */ |
156 for (i = 0; i < h.e_phnum; i++) { | 222 for (i = 0; i < phnum; i++) { |
157 const Elf_Phdr *p = &ncf->pheaders[i]; | 223 const Elf_Phdr *p = &ncf->pheaders[i]; |
158 if (p->p_type != PT_LOAD) continue; | 224 if (p->p_type != PT_LOAD) continue; |
159 if (0 == (ncf->pheaders[i].p_flags & PF_X)) continue; | 225 if (0 == (ncf->pheaders[i].p_flags & PF_X)) continue; |
160 | 226 |
161 /* TODO(karl) Remove the cast to off_t, or verify value in range. */ | 227 /* TODO(karl) Remove the cast to off_t, or verify value in range. */ |
162 nread = readat(ncf, fd, &(ncf->data[p->p_vaddr - ncf->vbase]), | 228 nread = readat(ncf, fd, &(ncf->data[p->p_vaddr - ncf->vbase]), |
163 (off_t) p->p_filesz, (off_t) p->p_offset); | 229 (off_t) p->p_filesz, (off_t) p->p_offset); |
164 if (nread < 0 || (size_t) nread < p->p_filesz) { | 230 if (nread < 0 || (size_t) nread < p->p_filesz) { |
165 ncf->error_fn( | 231 ncf->error_fn( |
166 "nc_load(%s): could not read segment %d (%d < %" | 232 "nc_load(%s): could not read segment %d (%d < %" |
167 NACL_PRIuElf_Xword")\n", | 233 NACL_PRIuElf_Xword")\n", |
168 ncf->fname, i, (int)nread, p->p_filesz); | 234 ncf->fname, i, (int)nread, p->p_filesz); |
169 return -1; | 235 return -1; |
170 } | 236 } |
171 } | 237 } |
| 238 |
172 /* load the section headers */ | 239 /* load the section headers */ |
173 ncf->shnum = h.e_shnum; | 240 ncf->shnum = shnum; |
174 shsize = ncf->shnum * sizeof(*ncf->sheaders); | 241 shsize = ncf->shnum * sizeof(*ncf->sheaders); |
175 ncf->sheaders = (Elf_Shdr *)calloc(1, shsize); | 242 ncf->sheaders = (Elf_Shdr *)calloc(1, shsize); |
176 if (NULL == ncf->sheaders) { | 243 if (NULL == ncf->sheaders) { |
177 ncf->error_fn("nc_load(%s): calloc(1, %"NACL_PRIdS") failed\n", | 244 ncf->error_fn("nc_load(%s): calloc(1, %"NACL_PRIdS") failed\n", |
178 ncf->fname, shsize); | 245 ncf->fname, shsize); |
179 return -1; | 246 return -1; |
180 } | 247 } |
181 /* TODO(karl) Remove the cast to size_t, or verify value in range. */ | 248 #if NACL_TARGET_SUBARCH == 64 |
182 nread = readat(ncf, fd, ncf->sheaders, (off_t) shsize, (off_t) h.e_shoff); | 249 if (h.h32.e_ident[EI_CLASS] == ELFCLASS64) { |
183 if (nread < 0 || (size_t) nread < shsize) { | 250 /* |
184 ncf->error_fn("nc_load(%s): could not read section headers\n", | 251 * Read 64-bit section headers and convert them. |
185 ncf->fname); | 252 */ |
186 return -1; | 253 Elf64_Shdr *shdr64 = (Elf64_Shdr *)calloc(shnum, sizeof(shdr64[0])); |
| 254 if (NULL == shdr64) { |
| 255 ncf->error_fn( |
| 256 "nc_load(%s): calloc(%"NACL_PRIdS", %"NACL_PRIdS") failed\n", |
| 257 ncf->fname, (size_t) shnum, sizeof(shdr64[0])); |
| 258 return -1; |
| 259 } |
| 260 shsize = ncf->shnum * sizeof(shdr64[0]); |
| 261 nread = readat(ncf, fd, shdr64, (off_t) shsize, (off_t) shoff); |
| 262 if (nread < 0 || (size_t) nread < shsize) { |
| 263 ncf->error_fn("nc_load(%s): could not read section headers\n", |
| 264 ncf->fname); |
| 265 return -1; |
| 266 } |
| 267 for (i = 0; i < shnum; ++i) { |
| 268 if (shdr64[i].sh_flags > 0xffffffffU || |
| 269 shdr64[i].sh_size > 0xffffffffU || |
| 270 shdr64[i].sh_addralign > 0xffffffffU || |
| 271 shdr64[i].sh_entsize > 0xffffffffU) { |
| 272 ncf->error_fn("nc_load(%s): shdr[%d] fields overflow 32 bits\n", |
| 273 ncf->fname, i); |
| 274 return -1; |
| 275 } |
| 276 ncf->sheaders[i].sh_name = shdr64[i].sh_name; |
| 277 ncf->sheaders[i].sh_type = shdr64[i].sh_type; |
| 278 ncf->sheaders[i].sh_flags = (Elf32_Word) shdr64[i].sh_flags; |
| 279 ncf->sheaders[i].sh_addr = (Elf32_Addr) shdr64[i].sh_addr; |
| 280 ncf->sheaders[i].sh_offset = (Elf32_Off) shdr64[i].sh_offset; |
| 281 ncf->sheaders[i].sh_size = (Elf32_Word) shdr64[i].sh_size; |
| 282 ncf->sheaders[i].sh_link = shdr64[i].sh_link; |
| 283 ncf->sheaders[i].sh_info = shdr64[i].sh_info; |
| 284 ncf->sheaders[i].sh_addralign = (Elf32_Word) shdr64[i].sh_addralign; |
| 285 ncf->sheaders[i].sh_entsize = (Elf32_Word) shdr64[i].sh_entsize; |
| 286 } |
| 287 free(shdr64); |
| 288 } else |
| 289 #endif |
| 290 { |
| 291 /* TODO(karl) Remove the cast to size_t, or verify value in range. */ |
| 292 nread = readat(ncf, fd, ncf->sheaders, (off_t) shsize, (off_t) shoff); |
| 293 if (nread < 0 || (size_t) nread < shsize) { |
| 294 ncf->error_fn("nc_load(%s): could not read section headers\n", |
| 295 ncf->fname); |
| 296 return -1; |
| 297 } |
187 } | 298 } |
188 | 299 |
189 /* success! */ | 300 /* success! */ |
190 return 0; | 301 return 0; |
191 } | 302 } |
192 | 303 |
193 ncfile *nc_loadfile_depending(const char *filename, | 304 ncfile *nc_loadfile_depending(const char *filename, |
194 nc_loadfile_error_fn error_fn) { | 305 nc_loadfile_error_fn error_fn) { |
195 ncfile *ncf; | 306 ncfile *ncf; |
196 int fd; | 307 int fd; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 for (ii = 0; ii < ncf->shnum; ii++) { | 357 for (ii = 0; ii < ncf->shnum; ii++) { |
247 if ((ncf->sheaders[ii].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR) { | 358 if ((ncf->sheaders[ii].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR) { |
248 if (ncf->sheaders[ii].sh_addr < base) base = ncf->sheaders[ii].sh_addr; | 359 if (ncf->sheaders[ii].sh_addr < base) base = ncf->sheaders[ii].sh_addr; |
249 if (ncf->sheaders[ii].sh_addr + ncf->sheaders[ii].sh_size > limit) | 360 if (ncf->sheaders[ii].sh_addr + ncf->sheaders[ii].sh_size > limit) |
250 limit = ncf->sheaders[ii].sh_addr + ncf->sheaders[ii].sh_size; | 361 limit = ncf->sheaders[ii].sh_addr + ncf->sheaders[ii].sh_size; |
251 } | 362 } |
252 } | 363 } |
253 *vbase = base; | 364 *vbase = base; |
254 *vlimit = limit; | 365 *vlimit = limit; |
255 } | 366 } |
OLD | NEW |