1 : /*
2 : * Copyright (c) 2012 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 <stdio.h>
8 : #include <stdlib.h>
9 : #include <string.h>
10 :
11 : #include "native_client/src/include/elf.h"
12 : #include "native_client/src/include/elf_constants.h"
13 : #include "native_client/src/shared/platform/nacl_check.h"
14 : #include "native_client/src/trusted/validator/driver/elf_load.h"
15 :
16 :
17 : namespace elf_load {
18 :
19 1 : void ReadImage(const char *filename, Image *image) {
20 1 : FILE *fp = fopen(filename, "rb");
21 1 : if (fp == NULL) {
22 0 : printf("Failed to open input file: %s\n", filename);
23 0 : exit(1);
24 : }
25 :
26 1 : fseek(fp, 0, SEEK_END);
27 1 : size_t file_size = ftell(fp);
28 :
29 1 : image->resize(file_size);
30 :
31 1 : fseek(fp, 0, SEEK_SET);
32 1 : size_t got = fread(&(*image)[0], 1, file_size, fp);
33 1 : if (got != file_size) {
34 0 : printf("Unable to read image from input file: %s\n", filename);
35 0 : exit(1);
36 : }
37 1 : fclose(fp);
38 1 : }
39 :
40 :
41 : template<typename ElfEhdrType, typename ElfPhdrType>
42 2 : Segment FindTextSegment(const Image &image) {
43 : // Initialization only to suppress 'uninitialized' warning.
44 2 : Segment segment = {NULL, 0, 0};
45 2 : bool found = false;
46 :
47 2 : const ElfEhdrType &header = *reinterpret_cast<const ElfEhdrType *>(&image[0]);
48 2 : CHECK(sizeof(header) <= image.size());
49 2 : CHECK(memcmp(header.e_ident, ELFMAG, SELFMAG) == 0);
50 :
51 2 : for (uint64_t index = 0; index < header.e_phnum; ++index) {
52 2 : uint64_t phdr_offset = header.e_phoff + header.e_phentsize * index;
53 : // static_cast to silence msvc on 32-bit platform
54 : const ElfPhdrType &phdr = *reinterpret_cast<const ElfPhdrType *>(
55 2 : &image[static_cast<size_t>(phdr_offset)]);
56 :
57 : // TODO(shcherbina): size of other loadable segments
58 2 : if (phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X)) {
59 2 : if (found) {
60 0 : printf("More than one text segment.\n");
61 0 : exit(1);
62 : }
63 :
64 2 : if (phdr.p_flags != (PF_R | PF_X)) {
65 : // Cast to support 64-bit ELF.
66 : printf("Text segment is expected to have flags PF_R | PF_X "
67 : "(has 0x%" NACL_PRIx64 " instead).\n",
68 0 : static_cast<uint64_t>(phdr.p_flags));
69 0 : exit(1);
70 : }
71 :
72 2 : CHECK(phdr.p_filesz <= phdr.p_memsz);
73 2 : if (phdr.p_filesz < phdr.p_memsz) {
74 0 : printf("File image is smaller than memory image size.\n");
75 0 : exit(1);
76 : }
77 :
78 : // TODO(shcherbina): find or introduce proper constant.
79 2 : if (phdr.p_filesz > 256 << 20) {
80 0 : printf("Test segment is too large.\n");
81 0 : exit(1);
82 : }
83 :
84 2 : if (phdr.p_vaddr > UINT32_MAX - phdr.p_filesz) {
85 0 : printf("Text segment does not fit in 4GB.\n");
86 0 : exit(1);
87 : }
88 :
89 2 : segment.data = &image[static_cast<size_t>(phdr.p_offset)];
90 2 : segment.size = static_cast<uint32_t>(phdr.p_filesz);
91 2 : segment.vaddr = static_cast<uint32_t>(phdr.p_vaddr);
92 2 : found = true;
93 : }
94 2 : }
95 2 : if (!found) {
96 0 : printf("Text segment not found.\n");
97 0 : exit(1);
98 : }
99 2 : return segment;
100 2 : }
101 :
102 :
103 1 : Architecture GetElfArch(const Image &image) {
104 : // e_machine field is the same for Elf32_Ehdr and Elf64_Ehdr.
105 1 : const Elf32_Ehdr &header = *reinterpret_cast<const Elf32_Ehdr *>(&image[0]);
106 1 : switch (header.e_machine) {
107 : case EM_386:
108 1 : return X86_32;
109 : case EM_X86_64:
110 1 : return X86_64;
111 : case EM_ARM:
112 0 : return ARM;
113 : default:
114 0 : printf("Unsupported e_machine %" NACL_PRIu16 ".\n", header.e_machine);
115 0 : exit(1);
116 : }
117 1 : }
118 :
119 :
120 1 : Segment GetElfTextSegment(const Image &image) {
121 : // We don't know in advance whether it's elf32 or elf64, but we are only
122 : // looking at few first fields of the header, and they are the same for
123 : // Elf32_Ehdr and Elf64_Ehdr.
124 1 : const Elf32_Ehdr &header = *reinterpret_cast<const Elf32_Ehdr *>(&image[0]);
125 : if (image.size() < sizeof(header) ||
126 1 : memcmp(header.e_ident, ELFMAG, SELFMAG) != 0) {
127 0 : printf("Not an ELF file.\n");
128 0 : exit(1);
129 : }
130 :
131 : Segment segment;
132 1 : switch (header.e_ident[EI_CLASS]) {
133 : case ELFCLASS32:
134 1 : segment = FindTextSegment<Elf32_Ehdr, Elf32_Phdr>(image);
135 1 : break;
136 : case ELFCLASS64:
137 1 : segment = FindTextSegment<Elf64_Ehdr, Elf64_Phdr>(image);
138 1 : break;
139 : default:
140 0 : printf("Invalid ELF class %d.\n", header.e_ident[EI_CLASS]);
141 0 : exit(1);
142 : }
143 :
144 1 : return segment;
145 1 : }
146 :
147 : } // namespace elf_load
|