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

Side by Side Diff: src/untrusted/irt/tls_edit.c

Issue 140653005: Adds tls_edit utility which patches irt_core.nexe's TLS usage. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/native_client
Patch Set: Applied suggestions from Mark Created 6 years, 10 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/untrusted/irt/nacl.scons ('k') | tests/irt_compatibility/nacl.scons » ('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 /*
8 * This alters instructions for the IRT so that access to the TLS
9 * point to the IRT's TLS.
10 */
11
12
13 #include <errno.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <sys/stat.h>
17
18 #include "native_client/src/include/elf32.h"
19 #include "native_client/src/include/elf64.h"
20 #include "native_client/src/include/arm_sandbox.h"
21 #include "native_client/src/include/portability.h"
22 #include "native_client/src/trusted/validator_ragel/validator.h"
23
24 static void *g_contents;
25 static size_t g_contents_size;
26 static uint8_t *g_code_start;
27 static uint32_t g_code_addr;
28 static int g_errors;
29 static int g_changes;
30
31 static uint32_t GetInsnAddr(const void *insn) {
32 return (uint32_t) ((uint8_t *) insn - g_code_start) + g_code_addr;
33 }
34
35 static void ReportError(const void *insn, const char *message) {
36 uint32_t insn_addr = GetInsnAddr(insn);
37
38 fprintf(stderr, "%#x: %s\n", (unsigned int) insn_addr, message);
39 ++g_errors;
40 }
41
42 static void EditArmCode(void *code, size_t code_length) {
43 Elf32_Word *const words = code;
44 Elf32_Word *const end = (void *) ((uint8_t *) code + code_length);
45 Elf32_Word *insn;
46
47 for (insn = words; insn < end; ++insn) {
48 if (*insn == NACL_INSTR_ARM_LITERAL_POOL_HEAD) {
49 if ((insn - words) % 4 != 0) {
50 ReportError(insn, "Roadblock not at start of bundle");
51 } else {
52 /*
53 * Ignore the rest of this bundle.
54 */
55 insn += 3;
56 }
57 } else if ((*insn & 0x0FFF0FFF) == 0x05990000) {
58 /*
59 * This is 'ldr REG, [r9, #0]'.
60 * Turn it into 'ldr REG, [r9, #4]'.
61 */
62 *insn |= 4;
63 ++g_changes;
64 }
65 }
66 }
67
68 static Bool ConsiderOneInsn(const uint8_t *insn_begin, const uint8_t *insn_end,
69 uint32_t validation_info, void *data) {
70 UNREFERENCED_PARAMETER(data);
71 if (insn_begin[0] == 0x65) { /* GS prefix */
72 if (insn_end - insn_begin < 6) {
73 ReportError(insn_begin, "Unexpected GS prefix");
74 } else if (insn_end[-1] == 0 && insn_end[-2] == 0 &&
75 insn_end[-3] == 0 && insn_end[-4] == 0) {
76 /*
77 * This is 'something %gs:0'.
78 * Turn it into 'something %gs:4'.
79 */
80 ((uint8_t *) insn_end)[-4] = 4;
81 ++g_changes;
82 } else if (insn_end[-1] == 0 && insn_end[-2] == 0 &&
83 insn_end[-3] == 0 && insn_end[-4] == 4) {
84 /*
85 * The Instruction is already offset to the right location.
86 * TODO(dyen): This case should be removed eventually once the IRT
87 * is being properly compiled without any special TLS flags.
88 */
89 uint32_t insn_addr = GetInsnAddr(insn_begin);
90 printf("%#x: %%gs address already pointing to correct offset (4)\n",
91 insn_addr);
92 } else {
93 ReportError(insn_begin, "Unexpected %gs address");
94 }
95 }
96 return (validation_info & (VALIDATION_ERRORS_MASK | BAD_JUMP_TARGET)) == 0;
97 }
98
99 static void EditX86_32Code(void *code, size_t code_length) {
100 const NaClCPUFeaturesX86 *cpu_features = &kFullCPUIDFeatures;
101 if (!ValidateChunkIA32(code, code_length,
102 CALL_USER_CALLBACK_ON_EACH_INSTRUCTION,
103 cpu_features, &ConsiderOneInsn, NULL))
104 ReportError(code, "Validation failed");
105 }
106
107 static void ReadInput(const char *filename) {
108 struct stat st;
109 FILE *fp = fopen(filename, "rb");
110 if (fp == NULL) {
111 fprintf(stderr, "fopen: %s: %s\n",
112 filename, strerror(errno));
113 exit(1);
114 }
115
116 if (fstat(fileno(fp), &st) < 0) {
117 fprintf(stderr, "fstat: %s: %s\n",
118 filename, strerror(errno));
119 exit(1);
120 }
121
122 g_contents_size = st.st_size;
123 g_contents = malloc(g_contents_size);
124 if (g_contents == NULL) {
125 fprintf(stderr, "Cannot allocate %u bytes: %s\n",
126 (unsigned int) st.st_size, strerror(errno));
127 exit(1);
128 }
129
130 {
131 size_t read_bytes = fread(g_contents, 1, g_contents_size, fp);
132 if (read_bytes != g_contents_size) {
133 if (ferror(fp)) {
134 fprintf(stderr, "fread: %s: %s\n",
135 filename, strerror(errno));
136 } else if (feof(fp)) {
137 fprintf(stderr, "fread: %s: premature EOF\n",
138 filename);
139 } else {
140 fprintf(stderr, "fread: %s: unexpected read count - %u != %u\n",
141 filename, (unsigned int) read_bytes,
142 (unsigned int) g_contents_size);
143 }
144 exit(1);
145 }
146 }
147
148 fclose(fp);
149 }
150
151 static void WriteOutput(const char *filename) {
152 FILE *fp = fopen(filename, "wb+");
153 if (fp == NULL) {
154 fprintf(stderr, "fopen: %s: %s\n", filename, strerror(errno));
155 exit(1);
156 }
157
158 {
159 size_t nwrote = fwrite(g_contents, 1, g_contents_size, fp);
160 if (nwrote != g_contents_size) {
161 fprintf(stderr, "fwrite: %s: %s\n", filename, strerror(errno));
162 exit(1);
163 }
164 }
165
166 fclose(fp);
167 }
168
169 static Bool EditTLSCode(const char *infile, uint32_t code_addr,
170 uint8_t *code_start, size_t code_length,
171 uint16_t e_machine) {
172 g_code_addr = code_addr;
173 g_code_start = code_start;
174
175 switch (e_machine) {
176 case EM_ARM:
177 EditArmCode(g_code_start, code_length);
178 break;
179 case EM_386:
180 EditX86_32Code(g_code_start, code_length);
181 break;
182 case EM_X86_64:
183 printf("%s: x86-64 ELF detected, no instructions changed\n",
184 infile);
185 return TRUE;
186 case EM_MIPS:
187 printf("%s: MIP ELF detected, no instructions changed\n",
Roland McGrath 2014/02/04 17:49:31 typo: MIPS
188 infile);
189 return TRUE;
190 default:
191 fprintf(stderr, "%s: Unsupported e_machine %d\n",
192 infile, e_machine);
193 return FALSE;
194 }
195
196 if (g_changes == 0) {
197 printf("%s: Found no changes to make\n",
198 infile);
199 return TRUE;
200 } else {
201 printf("%s: %d instructions changed\n",
202 infile, g_changes);
203 }
204
205 return TRUE;
206 }
207
208 static Bool Process32BitFile(const char *infile) {
209 const Elf32_Ehdr *ehdr;
210 const Elf32_Phdr *phdr;
211 int i;
212
213 ehdr = g_contents;
214 if (ehdr->e_phoff > g_contents_size) {
215 fprintf(stderr, "%s: bogus e_phoff\n",
216 infile);
217 return FALSE;
218 }
219 if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
220 fprintf(stderr, "%s: not an ELFCLASS32 file\n",
221 infile);
222 return FALSE;
223 }
224 if (ehdr->e_phentsize != sizeof(Elf32_Phdr)) {
225 fprintf(stderr, "%s: wrong e_phentsize: %u\n",
226 infile, ehdr->e_phentsize);
227 return FALSE;
228 }
229 if (g_contents_size - ehdr->e_phoff < ehdr->e_phnum * sizeof(Elf32_Phdr)) {
230 fprintf(stderr, "%s: bogus elf32 e_phnum\n",
231 infile);
232 return FALSE;
233 }
234
235 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
236 fprintf(stderr, "%s: not an ELFDATA2LSB file\n",
237 infile);
238 return FALSE;
239 }
240
241 phdr = (const void *) ((uint8_t *) g_contents + ehdr->e_phoff);
242 for (i = 0; i < ehdr->e_phnum; ++i) {
243 if (phdr[i].p_type == PT_LOAD && (phdr[i].p_flags & PF_X) != 0)
244 break;
245 }
246 if (i == ehdr->e_phnum) {
247 fprintf(stderr, "%s: Could not find executable load segment!\n",
248 infile);
249 return FALSE;
250 }
251
252 if (phdr[i].p_offset > g_contents_size ||
253 g_contents_size - phdr[i].p_offset < phdr[i].p_filesz) {
254 fprintf(stderr, "%s: Program header %d has invalid offset or size!\n",
255 infile, i);
256 return FALSE;
257 }
258
259 return EditTLSCode(infile, phdr[i].p_vaddr,
260 (uint8_t *) g_contents + phdr[i].p_offset,
261 phdr[i].p_filesz, ehdr->e_machine);
262 }
263
264 static Bool Process64BitFile(const char *infile) {
265 const Elf64_Ehdr *ehdr;
266 const Elf64_Phdr *phdr;
267 int i;
268
269 ehdr = g_contents;
270 if (ehdr->e_phoff > g_contents_size) {
271 fprintf(stderr, "%s: bogus e_phoff\n",
272 infile);
273 return FALSE;
274 }
275 if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) {
276 fprintf(stderr, "%s: not an ELFCLASS64 file\n",
277 infile);
278 return FALSE;
279 }
280 if (ehdr->e_phentsize != sizeof(Elf64_Phdr)) {
281 fprintf(stderr, "%s: wrong e_phentsize: %u\n",
282 infile, ehdr->e_phentsize);
283 return FALSE;
284 }
285 if (g_contents_size - ehdr->e_phoff < ehdr->e_phnum * sizeof(Elf64_Phdr)) {
286 fprintf(stderr, "%s: bogus elf64 e_phnum\n",
287 infile);
288 return FALSE;
289 }
290
291 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
292 fprintf(stderr, "%s: not an ELFDATA2LSB file\n",
293 infile);
294 return FALSE;
295 }
296
297 phdr = (const void *) ((uint8_t *) g_contents + ehdr->e_phoff);
298 for (i = 0; i < ehdr->e_phnum; ++i) {
299 if (phdr[i].p_type == PT_LOAD && (phdr[i].p_flags & PF_X) != 0)
300 break;
301 }
302 if (i == ehdr->e_phnum) {
303 fprintf(stderr, "%s: Could not find executable load segment!\n",
304 infile);
305 return FALSE;
306 }
307
308 if (phdr[i].p_offset > g_contents_size ||
309 g_contents_size - phdr[i].p_offset < phdr[i].p_filesz) {
310 fprintf(stderr, "%s: Program header %d has invalid offset or size!\n",
311 infile, i);
312 return FALSE;
313 }
314
315 return EditTLSCode(infile, (uint32_t) phdr[i].p_vaddr,
316 (uint8_t *) g_contents + phdr[i].p_offset,
317 (size_t) phdr[i].p_filesz, ehdr->e_machine);
318 }
319
320 int main(int argc, char **argv) {
321 const char *infile;
322 const char *outfile;
323
324 if (argc != 3) {
325 fprintf(stderr, "Usage: %s INFILE OUTFILE\n", argv[0]);
326 return 1;
327 }
328
329 infile = argv[1];
330 outfile = argv[2];
331
332 ReadInput(infile);
333
334 if (g_contents_size < SELFMAG) {
335 fprintf(stderr, "%s: too short to be an ELF file\n",
336 infile);
337 return 1;
338 }
339 if (memcmp(g_contents, ELFMAG, SELFMAG) != 0) {
340 fprintf(stderr, "%s: not an ELF file\n",
341 infile);
342 return 1;
343 }
344
345 /*
346 * We will examine the header to figure out whether we are dealing
347 * with a 32 bit or 64 bit executable file.
348 */
349 if (g_contents_size >= sizeof(Elf32_Ehdr) &&
350 ((Elf32_Ehdr*) g_contents)->e_ident[EI_CLASS] == ELFCLASS32) {
351 if (!Process32BitFile(infile)) {
352 fprintf(stderr, "%s: Could not process 32 bit ELF file\n",
353 infile);
354 return 1;
355 }
356 } else if (g_contents_size >= sizeof(Elf64_Ehdr) &&
357 ((Elf64_Ehdr*) g_contents)->e_ident[EI_CLASS] == ELFCLASS64) {
358 if (!Process64BitFile(infile)) {
359 fprintf(stderr, "%s: Could not process 64 bit ELF file\n",
360 infile);
361 return 1;
362 }
363 } else {
364 fprintf(stderr, "%s: Invalid ELF file!\n",
365 infile);
366 return 1;
367 }
368
369 if (g_errors != 0)
370 return 1;
371
372 WriteOutput(outfile);
373 return 0;
374 }
OLDNEW
« no previous file with comments | « src/untrusted/irt/nacl.scons ('k') | tests/irt_compatibility/nacl.scons » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698