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.
8 * This alters instructions for the IRT so that access to the TLS
9 * point to the IRT's TLS.
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"
24 static Bool g_verbose = FALSE;
25 static void *g_contents;
26 static size_t g_contents_size;
27 static uint8_t *g_code_start;
28 static uint32_t g_code_addr;
32 static uint32_t GetInsnAddr(const void *insn) {
33 return (uint32_t) ((uint8_t *) insn - g_code_start) + g_code_addr;
36 static void ReportError(const void *insn, const char *message) {
37 uint32_t insn_addr = GetInsnAddr(insn);
39 fprintf(stderr, "%#x: %s\n", (unsigned int) insn_addr, message);
43 static void EditArmCode(void *code, size_t code_length) {
44 Elf32_Word *const words = code;
45 Elf32_Word *const end = (void *) ((uint8_t *) code + code_length);
48 for (insn = words; insn < end; ++insn) {
49 if (*insn == NACL_INSTR_ARM_LITERAL_POOL_HEAD) {
50 if ((insn - words) % 4 != 0) {
51 ReportError(insn, "Roadblock not at start of bundle");
54 * Ignore the rest of this bundle.
58 } else if ((*insn & 0x0FFF0FFF) == 0x05990000) {
60 * This is 'ldr REG, [r9, #0]'.
61 * Turn it into 'ldr REG, [r9, #4]'.
69 static Bool ConsiderOneInsn(const uint8_t *insn_begin, const uint8_t *insn_end,
70 uint32_t validation_info, void *data) {
71 UNREFERENCED_PARAMETER(data);
72 if (insn_begin[0] == 0x65) { /* GS prefix */
73 if (insn_end - insn_begin < 6) {
74 ReportError(insn_begin, "Unexpected GS prefix");
75 } else if (insn_end[-1] == 0 && insn_end[-2] == 0 &&
76 insn_end[-3] == 0 && insn_end[-4] == 0) {
78 * This is 'something %gs:0'.
79 * Turn it into 'something %gs:4'.
81 ((uint8_t *) insn_end)[-4] = 4;
83 } else if (insn_end[-1] == 0 && insn_end[-2] == 0 &&
84 insn_end[-3] == 0 && insn_end[-4] == 4) {
86 * The instruction is already offset to the right location.
87 * TODO(dyen): This case should be removed eventually once the IRT
88 * is being properly compiled without any special TLS flags.
90 uint32_t insn_addr = GetInsnAddr(insn_begin);
92 printf("%#x: %%gs address already pointing to correct offset (4)\n",
96 ReportError(insn_begin, "Unexpected %gs address");
99 return (validation_info & (VALIDATION_ERRORS_MASK | BAD_JUMP_TARGET)) == 0;
102 static void EditX86_32Code(void *code, size_t code_length) {
103 const NaClCPUFeaturesX86 *cpu_features = &kFullCPUIDFeatures;
104 if (!ValidateChunkIA32(code, code_length,
105 CALL_USER_CALLBACK_ON_EACH_INSTRUCTION,
106 cpu_features, &ConsiderOneInsn, NULL))
107 ReportError(code, "Validation failed");
110 static void ReadInput(const char *filename) {
114 FILE *fp = fopen(filename, "rb");
116 fprintf(stderr, "fopen: %s: %s\n",
117 filename, strerror(errno));
121 if (fstat(fileno(fp), &st) < 0) {
122 fprintf(stderr, "fstat: %s: %s\n",
123 filename, strerror(errno));
127 g_contents_size = st.st_size;
128 g_contents = malloc(g_contents_size);
129 if (g_contents == NULL) {
130 fprintf(stderr, "Cannot allocate %u bytes: %s\n",
131 (unsigned int) st.st_size, strerror(errno));
135 read_bytes = fread(g_contents, 1, g_contents_size, fp);
136 if (read_bytes != g_contents_size) {
138 fprintf(stderr, "fread: %s: %s\n",
139 filename, strerror(errno));
140 } else if (feof(fp)) {
141 fprintf(stderr, "fread: %s: premature EOF\n",
144 fprintf(stderr, "fread: %s: unexpected read count - %u != %u\n",
145 filename, (unsigned int) read_bytes,
146 (unsigned int) g_contents_size);
154 static void WriteOutput(const char *filename) {
157 FILE *fp = fopen(filename, "wb+");
159 fprintf(stderr, "fopen: %s: %s\n", filename, strerror(errno));
163 nwrote = fwrite(g_contents, 1, g_contents_size, fp);
164 if (nwrote != g_contents_size) {
165 fprintf(stderr, "fwrite: %s: %s\n", filename, strerror(errno));
172 static Bool EditTLSCode(const char *infile, uint32_t code_addr,
173 uint8_t *code_start, size_t code_length,
174 uint16_t e_machine) {
175 g_code_addr = code_addr;
176 g_code_start = code_start;
180 EditArmCode(g_code_start, code_length);
183 EditX86_32Code(g_code_start, code_length);
187 printf("%s: x86-64 ELF detected, no instructions changed\n",
193 printf("%s: MIPS ELF detected, no instructions changed\n",
198 fprintf(stderr, "%s: Unsupported e_machine %d\n",
204 if (g_changes == 0) {
205 printf("%s: Found no changes to make\n",
208 printf("%s: %d instructions changed\n",
216 static Bool Process32BitFile(const char *infile) {
217 const Elf32_Ehdr *ehdr;
218 const Elf32_Phdr *phdr;
222 if (ehdr->e_phoff > g_contents_size) {
223 fprintf(stderr, "%s: bogus e_phoff\n",
227 if (ehdr->e_ident[EI_CLASS] != ELFCLASS32) {
228 fprintf(stderr, "%s: not an ELFCLASS32 file\n",
232 if (ehdr->e_phentsize != sizeof(Elf32_Phdr)) {
233 fprintf(stderr, "%s: wrong e_phentsize: %u\n",
234 infile, ehdr->e_phentsize);
237 if (g_contents_size - ehdr->e_phoff < ehdr->e_phnum * sizeof(Elf32_Phdr)) {
238 fprintf(stderr, "%s: bogus elf32 e_phnum\n",
243 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
244 fprintf(stderr, "%s: not an ELFDATA2LSB file\n",
249 phdr = (const void *) ((uint8_t *) g_contents + ehdr->e_phoff);
250 for (i = 0; i < ehdr->e_phnum; ++i) {
251 if (phdr[i].p_type == PT_LOAD && (phdr[i].p_flags & PF_X) != 0)
254 if (i == ehdr->e_phnum) {
255 fprintf(stderr, "%s: Could not find executable load segment!\n",
260 if (phdr[i].p_offset > g_contents_size ||
261 g_contents_size - phdr[i].p_offset < phdr[i].p_filesz) {
262 fprintf(stderr, "%s: Program header %d has invalid offset or size!\n",
267 return EditTLSCode(infile, phdr[i].p_vaddr,
268 (uint8_t *) g_contents + phdr[i].p_offset,
269 phdr[i].p_filesz, ehdr->e_machine);
272 static Bool Process64BitFile(const char *infile) {
273 const Elf64_Ehdr *ehdr;
274 const Elf64_Phdr *phdr;
278 if (ehdr->e_phoff > g_contents_size) {
279 fprintf(stderr, "%s: bogus e_phoff\n",
283 if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) {
284 fprintf(stderr, "%s: not an ELFCLASS64 file\n",
288 if (ehdr->e_phentsize != sizeof(Elf64_Phdr)) {
289 fprintf(stderr, "%s: wrong e_phentsize: %u\n",
290 infile, ehdr->e_phentsize);
293 if (g_contents_size - ehdr->e_phoff < ehdr->e_phnum * sizeof(Elf64_Phdr)) {
294 fprintf(stderr, "%s: bogus elf64 e_phnum\n",
299 if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
300 fprintf(stderr, "%s: not an ELFDATA2LSB file\n",
305 phdr = (const void *) ((uint8_t *) g_contents + ehdr->e_phoff);
306 for (i = 0; i < ehdr->e_phnum; ++i) {
307 if (phdr[i].p_type == PT_LOAD && (phdr[i].p_flags & PF_X) != 0)
310 if (i == ehdr->e_phnum) {
311 fprintf(stderr, "%s: Could not find executable load segment!\n",
316 if (phdr[i].p_offset > g_contents_size ||
317 g_contents_size - phdr[i].p_offset < phdr[i].p_filesz) {
318 fprintf(stderr, "%s: Program header %d has invalid offset or size!\n",
323 return EditTLSCode(infile, (uint32_t) phdr[i].p_vaddr,
324 (uint8_t *) g_contents + phdr[i].p_offset,
325 (size_t) phdr[i].p_filesz, ehdr->e_machine);
328 int main(int argc, char **argv) {
333 for (arg_iter = 1; arg_iter < argc; ++arg_iter) {
334 if (argv[arg_iter][0] != '-')
337 if (0 == strcmp(argv[arg_iter], "--verbose")) {
340 fprintf(stderr, "Invalid option: %s", argv[arg_iter]);
345 if (argc - arg_iter != 2) {
346 fprintf(stderr, "Usage: %s [OPTIONS] INFILE OUTFILE\n", argv[0]);
347 fprintf(stderr, "\nOPTIONS:\n");
348 fprintf(stderr, "\t--verbose: Display verbose output messages\n");
352 infile = argv[arg_iter];
353 outfile = argv[arg_iter + 1];
357 if (g_contents_size < SELFMAG) {
358 fprintf(stderr, "%s: too short to be an ELF file\n",
362 if (memcmp(g_contents, ELFMAG, SELFMAG) != 0) {
363 fprintf(stderr, "%s: not an ELF file\n",
369 * We will examine the header to figure out whether we are dealing
370 * with a 32 bit or 64 bit executable file.
372 if (g_contents_size >= sizeof(Elf32_Ehdr) &&
373 ((Elf32_Ehdr *) g_contents)->e_ident[EI_CLASS] == ELFCLASS32) {
374 if (!Process32BitFile(infile)) {
375 fprintf(stderr, "%s: Could not process 32 bit ELF file\n",
379 } else if (g_contents_size >= sizeof(Elf64_Ehdr) &&
380 ((Elf64_Ehdr *) g_contents)->e_ident[EI_CLASS] == ELFCLASS64) {
381 if (!Process64BitFile(infile)) {
382 fprintf(stderr, "%s: Could not process 64 bit ELF file\n",
387 fprintf(stderr, "%s: Invalid ELF file!\n",
395 WriteOutput(outfile);