Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3)

Side by Side Diff: src/nonsfi/loader/elf_loader.c

Issue 269703002: Non-SFI Mode: Add nonsfi_loader and plumbing to test it (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: Cleanups Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/nonsfi/loader/build.scons ('k') | toolchain_build/pnacl_targetlibs.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2014 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7 #include <elf.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <link.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/mman.h>
16 #include <unistd.h>
17
18 #include "native_client/src/nonsfi/irt/irt_interfaces.h"
19 #include "native_client/src/shared/platform/nacl_log.h"
20 #include "native_client/src/trusted/service_runtime/nacl_config.h"
21
22
23 #define PAGE_SIZE 0x1000
bradn 2014/05/02 17:39:11 There's an odd irony in baking this in given it wo
Mark Seaborn 2014/05/02 18:18:50 Since you mention it, I've added a comment.
24 #define PAGE_MASK (PAGE_SIZE - 1)
25 #define MAX_PHNUM 128
26
27 static uintptr_t PageSizeRoundDown(uintptr_t addr) {
28 return addr & ~PAGE_MASK;
29 }
30
31 static uintptr_t PageSizeRoundUp(uintptr_t addr) {
32 return PageSizeRoundDown(addr + PAGE_SIZE - 1);
33 }
34
35 static int ElfFlagsToMmapFlags(int pflags) {
36 return ((pflags & PF_X) != 0 ? PROT_EXEC : 0) |
37 ((pflags & PF_R) != 0 ? PROT_READ : 0) |
38 ((pflags & PF_W) != 0 ? PROT_WRITE : 0);
39 }
40
41 static void CheckElfHeaders(ElfW(Ehdr) *ehdr) {
42 if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
43 NaClLog(LOG_FATAL, "Not an ELF file: no ELF header\n");
44 }
45 if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
46 NaClLog(LOG_FATAL, "Unexpected ELF class: not ELFCLASS32\n");
47 }
48 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
49 NaClLog(LOG_FATAL, "Not a little-endian ELF file\n");
50 }
51 if (ehdr->e_type != ET_DYN) {
52 NaClLog(LOG_FATAL, "Not a relocatable ELF object (not ET_DYN)\n");
53 }
54 if (ehdr->e_machine != NACL_ELF_E_MACHINE) {
55 NaClLog(LOG_FATAL, "Unexpected ELF e_machine field\n");
56 }
57 if (ehdr->e_version != EV_CURRENT) {
58 NaClLog(LOG_FATAL, "Unexpected ELF e_version field\n");
59 }
60 if (ehdr->e_ehsize != sizeof(*ehdr)) {
61 NaClLog(LOG_FATAL, "Unexpected ELF e_ehsize field\n");
62 }
63 if (ehdr->e_phentsize != sizeof(ElfW(Phdr))) {
64 NaClLog(LOG_FATAL, "Unexpected ELF e_phentsize field\n");
65 }
66 }
67
68 static uintptr_t LoadElfFile(const char *filename) {
69 int fd = open(filename, O_RDONLY);
70 if (fd < 0) {
71 NaClLog(LOG_FATAL, "Failed to open %s: %s\n", filename, strerror(errno));
72 }
73
74 /* Read ELF file headers. */
75 ElfW(Ehdr) ehdr;
76 ssize_t bytes_read = pread(fd, &ehdr, sizeof(ehdr), 0);
77 if (bytes_read != sizeof(ehdr)) {
78 NaClLog(LOG_FATAL, "Failed to read ELF file headers\n");
79 }
80 CheckElfHeaders(&ehdr);
81
82 /* Read ELF program headers. */
83 if (ehdr.e_phnum > MAX_PHNUM) {
84 NaClLog(LOG_FATAL, "ELF file has too many program headers\n");
85 }
86 ElfW(Phdr) phdr[MAX_PHNUM];
87 ssize_t phdrs_size = sizeof(phdr[0]) * ehdr.e_phnum;
88 bytes_read = pread(fd, phdr, phdrs_size, ehdr.e_phoff);
89 if (bytes_read != phdrs_size) {
90 NaClLog(LOG_FATAL, "Failed to read ELF program headers\n");
91 }
92
93 /* Find the first PT_LOAD segment. */
94 size_t i = 0;
bradn 2014/05/02 17:39:11 Given you're using i beyond the loop, maybe a more
Mark Seaborn 2014/05/02 18:18:50 Done.
95 while (i < ehdr.e_phnum && phdr[i].p_type != PT_LOAD)
96 ++i;
97 if (i == ehdr.e_phnum) {
98 NaClLog(LOG_FATAL, "ELF file has no PT_LOAD header\n");
99 }
100
101 /*
102 * ELF requires that PT_LOAD segments be in ascending order of p_vaddr.
103 * Find the last one to calculate the whole address span of the image.
104 */
105 ElfW(Phdr) *first_load = &phdr[i];
106 ElfW(Phdr) *last_load = &phdr[ehdr.e_phnum - 1];
107 while (last_load > first_load && last_load->p_type != PT_LOAD)
108 --last_load;
109
110 if (first_load->p_vaddr != 0) {
111 NaClLog(LOG_FATAL, "First PT_LOAD segment's load address is not 0\n");
112 }
113 size_t span = last_load->p_vaddr + last_load->p_memsz;
114
115 /* Reserve address space. */
116 void *mapping = mmap(NULL, span, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE,
117 -1, 0);
118 if (mapping == MAP_FAILED) {
119 NaClLog(LOG_FATAL, "Failed to reserve address space for executable\n");
120 }
121 uintptr_t load_bias = (uintptr_t) mapping;
122
123 uintptr_t prev_segment_end = 0;
124 ElfW(Phdr) *ph;
125 for (ph = first_load; ph <= last_load; ++ph) {
126 if (ph->p_type == PT_LOAD) {
bradn 2014/05/02 17:39:11 might be more readable with continue, to avoid the
Mark Seaborn 2014/05/02 18:18:50 Done.
127 int prot = ElfFlagsToMmapFlags(ph->p_flags);
128 uintptr_t segment_start = PageSizeRoundDown(ph->p_vaddr);
129 uintptr_t segment_end = PageSizeRoundUp(ph->p_vaddr + ph->p_memsz);
130 if (segment_start < prev_segment_end) {
131 NaClLog(LOG_FATAL, "PT_LOAD segments overlap or are not sorted\n");
132 }
133 prev_segment_end = segment_end;
134 void *segment_addr = (void *) (load_bias + segment_start);
135 void *map_result = mmap((void *) segment_addr,
136 segment_end - segment_start,
137 prot, MAP_PRIVATE | MAP_FIXED, fd,
138 PageSizeRoundDown(ph->p_offset));
139 if (map_result != segment_addr) {
140 NaClLog(LOG_FATAL, "Failed to map ELF segment\n");
141 }
142
143 /* Handle the BSS. */
144 if (ph->p_memsz < ph->p_filesz) {
145 NaClLog(LOG_FATAL, "Bad ELF segment: p_memsz < p_filesz\n");
146 }
147 if (ph->p_memsz > ph->p_filesz) {
148 if ((ph->p_flags & PF_W) == 0) {
149 NaClLog(LOG_FATAL,
150 "Bad ELF segment: non-writable segment with BSS\n");
151 }
152
153 uintptr_t bss_start = ph->p_vaddr + ph->p_filesz;
154 uintptr_t bss_map_start = PageSizeRoundUp(bss_start);
155 /*
156 * Zero the BSS to the end of the page.
157 *
158 * Zeroing beyond p_memsz might be more than is necessary for
159 * Non-SFI NaCl. On Linux, programs such as ld.so use the rest of
160 * the page, after p_memsz, as part of the brk() heap and assume
161 * that it has been zeroed. Non-SFI NaCl does not provide a brk()
162 * heap, though. However, zeroing to the end of the page is simple
163 * enough, and it's consistent with the case in additional pages
164 * must be mapped, which will all be fully zeroed.
165 */
166 memset((void *) (load_bias + bss_start), 0, bss_map_start - bss_start);
167
168 if (bss_map_start < segment_end) {
169 void *map_addr = (void *) (load_bias + bss_map_start);
170 map_result = mmap(map_addr, segment_end - bss_map_start,
171 prot, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
172 -1, 0);
173 if (map_result != map_addr) {
174 NaClLog(LOG_FATAL, "Failed to map BSS for ELF segment\n");
175 }
176 }
177 }
178 }
179 }
180
181 if (close(fd) != 0) {
182 NaClLog(LOG_FATAL, "close() failed\n");
183 }
184
185 return load_bias + ehdr.e_entry;
bradn 2014/05/02 17:39:11 Check it's in one of the sections?
Mark Seaborn 2014/05/02 18:18:50 OK. I've even checked that it's in an executable
186 }
187
188 int main(int argc, char **argv, char **environ) {
189 if (argc < 2) {
190 fprintf(stderr, "Usage: %s <executable> <args...>\n", argv[0]);
191 return 1;
192 }
193 const char *nexe_filename = argv[1];
194 uintptr_t entry = LoadElfFile(nexe_filename);
195 return nacl_irt_nonsfi_entry(argc, argv, environ, (nacl_entry_func_t) entry);
196 }
OLDNEW
« no previous file with comments | « src/nonsfi/loader/build.scons ('k') | toolchain_build/pnacl_targetlibs.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698