Commit | Line | Data |
---|---|---|
8512287a NL |
1 | /* |
2 | * Copyright 2015 Mentor Graphics Corporation. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License | |
6 | * as published by the Free Software Foundation; version 2 of the | |
7 | * License. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, but | |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | * General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | * | |
17 | * | |
18 | * vdsomunge - Host program which produces a shared object | |
19 | * architecturally specified to be usable by both soft- and hard-float | |
20 | * programs. | |
21 | * | |
22 | * The Procedure Call Standard for the ARM Architecture (ARM IHI | |
23 | * 0042E) says: | |
24 | * | |
25 | * 6.4.1 VFP and Base Standard Compatibility | |
26 | * | |
27 | * Code compiled for the VFP calling standard is compatible with | |
28 | * the base standard (and vice-versa) if no floating-point or | |
29 | * containerized vector arguments or results are used. | |
30 | * | |
31 | * And ELF for the ARM Architecture (ARM IHI 0044E) (Table 4-2) says: | |
32 | * | |
33 | * If both EF_ARM_ABI_FLOAT_XXXX bits are clear, conformance to the | |
34 | * base procedure-call standard is implied. | |
35 | * | |
36 | * The VDSO is built with -msoft-float, as with the rest of the ARM | |
37 | * kernel, and uses no floating point arguments or results. The build | |
38 | * process will produce a shared object that may or may not have the | |
39 | * EF_ARM_ABI_FLOAT_SOFT flag set (it seems to depend on the binutils | |
40 | * version; binutils starting with 2.24 appears to set it). The | |
41 | * EF_ARM_ABI_FLOAT_HARD flag should definitely not be set, and this | |
42 | * program will error out if it is. | |
43 | * | |
44 | * If the soft-float flag is set, this program clears it. That's all | |
45 | * it does. | |
46 | */ | |
47 | ||
8512287a NL |
48 | #include <elf.h> |
49 | #include <errno.h> | |
8512287a | 50 | #include <fcntl.h> |
13ee9fdb | 51 | #include <stdarg.h> |
8512287a NL |
52 | #include <stdbool.h> |
53 | #include <stdio.h> | |
54 | #include <stdlib.h> | |
55 | #include <string.h> | |
56 | #include <sys/mman.h> | |
57 | #include <sys/stat.h> | |
58 | #include <sys/types.h> | |
59 | #include <unistd.h> | |
60 | ||
8a603f91 NS |
61 | #define swab16(x) \ |
62 | ((((x) & 0x00ff) << 8) | \ | |
63 | (((x) & 0xff00) >> 8)) | |
64 | ||
65 | #define swab32(x) \ | |
66 | ((((x) & 0x000000ff) << 24) | \ | |
67 | (((x) & 0x0000ff00) << 8) | \ | |
68 | (((x) & 0x00ff0000) >> 8) | \ | |
69 | (((x) & 0xff000000) << 24)) | |
70 | ||
8512287a NL |
71 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
72 | #define HOST_ORDER ELFDATA2LSB | |
73 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ | |
74 | #define HOST_ORDER ELFDATA2MSB | |
75 | #endif | |
76 | ||
77 | /* Some of the ELF constants we'd like to use were added to <elf.h> | |
78 | * relatively recently. | |
79 | */ | |
80 | #ifndef EF_ARM_EABI_VER5 | |
81 | #define EF_ARM_EABI_VER5 0x05000000 | |
82 | #endif | |
83 | ||
84 | #ifndef EF_ARM_ABI_FLOAT_SOFT | |
85 | #define EF_ARM_ABI_FLOAT_SOFT 0x200 | |
86 | #endif | |
87 | ||
88 | #ifndef EF_ARM_ABI_FLOAT_HARD | |
89 | #define EF_ARM_ABI_FLOAT_HARD 0x400 | |
90 | #endif | |
91 | ||
13ee9fdb SN |
92 | static int failed; |
93 | static const char *argv0; | |
8512287a NL |
94 | static const char *outfile; |
95 | ||
13ee9fdb SN |
96 | static void fail(const char *fmt, ...) |
97 | { | |
98 | va_list ap; | |
99 | ||
100 | failed = 1; | |
101 | fprintf(stderr, "%s: ", argv0); | |
102 | va_start(ap, fmt); | |
103 | vfprintf(stderr, fmt, ap); | |
104 | va_end(ap); | |
105 | exit(EXIT_FAILURE); | |
106 | } | |
107 | ||
8512287a NL |
108 | static void cleanup(void) |
109 | { | |
13ee9fdb | 110 | if (failed && outfile != NULL) |
8512287a NL |
111 | unlink(outfile); |
112 | } | |
113 | ||
114 | static Elf32_Word read_elf_word(Elf32_Word word, bool swap) | |
115 | { | |
8a603f91 | 116 | return swap ? swab32(word) : word; |
8512287a NL |
117 | } |
118 | ||
119 | static Elf32_Half read_elf_half(Elf32_Half half, bool swap) | |
120 | { | |
8a603f91 | 121 | return swap ? swab16(half) : half; |
8512287a NL |
122 | } |
123 | ||
124 | static void write_elf_word(Elf32_Word val, Elf32_Word *dst, bool swap) | |
125 | { | |
8a603f91 | 126 | *dst = swap ? swab32(val) : val; |
8512287a NL |
127 | } |
128 | ||
129 | int main(int argc, char **argv) | |
130 | { | |
131 | const Elf32_Ehdr *inhdr; | |
132 | bool clear_soft_float; | |
133 | const char *infile; | |
134 | Elf32_Word e_flags; | |
135 | const void *inbuf; | |
136 | struct stat stat; | |
137 | void *outbuf; | |
138 | bool swap; | |
139 | int outfd; | |
140 | int infd; | |
141 | ||
142 | atexit(cleanup); | |
13ee9fdb | 143 | argv0 = argv[0]; |
8512287a NL |
144 | |
145 | if (argc != 3) | |
13ee9fdb | 146 | fail("Usage: %s [infile] [outfile]\n", argv[0]); |
8512287a NL |
147 | |
148 | infile = argv[1]; | |
149 | outfile = argv[2]; | |
150 | ||
151 | infd = open(infile, O_RDONLY); | |
152 | if (infd < 0) | |
13ee9fdb | 153 | fail("Cannot open %s: %s\n", infile, strerror(errno)); |
8512287a NL |
154 | |
155 | if (fstat(infd, &stat) != 0) | |
13ee9fdb | 156 | fail("Failed stat for %s: %s\n", infile, strerror(errno)); |
8512287a NL |
157 | |
158 | inbuf = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, infd, 0); | |
159 | if (inbuf == MAP_FAILED) | |
13ee9fdb | 160 | fail("Failed to map %s: %s\n", infile, strerror(errno)); |
8512287a NL |
161 | |
162 | close(infd); | |
163 | ||
164 | inhdr = inbuf; | |
165 | ||
166 | if (memcmp(&inhdr->e_ident, ELFMAG, SELFMAG) != 0) | |
13ee9fdb | 167 | fail("Not an ELF file\n"); |
8512287a NL |
168 | |
169 | if (inhdr->e_ident[EI_CLASS] != ELFCLASS32) | |
13ee9fdb | 170 | fail("Unsupported ELF class\n"); |
8512287a NL |
171 | |
172 | swap = inhdr->e_ident[EI_DATA] != HOST_ORDER; | |
173 | ||
174 | if (read_elf_half(inhdr->e_type, swap) != ET_DYN) | |
13ee9fdb | 175 | fail("Not a shared object\n"); |
8512287a | 176 | |
13ee9fdb SN |
177 | if (read_elf_half(inhdr->e_machine, swap) != EM_ARM) |
178 | fail("Unsupported architecture %#x\n", inhdr->e_machine); | |
8512287a NL |
179 | |
180 | e_flags = read_elf_word(inhdr->e_flags, swap); | |
181 | ||
182 | if (EF_ARM_EABI_VERSION(e_flags) != EF_ARM_EABI_VER5) { | |
13ee9fdb SN |
183 | fail("Unsupported EABI version %#x\n", |
184 | EF_ARM_EABI_VERSION(e_flags)); | |
8512287a NL |
185 | } |
186 | ||
187 | if (e_flags & EF_ARM_ABI_FLOAT_HARD) | |
13ee9fdb | 188 | fail("Unexpected hard-float flag set in e_flags\n"); |
8512287a NL |
189 | |
190 | clear_soft_float = !!(e_flags & EF_ARM_ABI_FLOAT_SOFT); | |
191 | ||
192 | outfd = open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); | |
193 | if (outfd < 0) | |
13ee9fdb | 194 | fail("Cannot open %s: %s\n", outfile, strerror(errno)); |
8512287a NL |
195 | |
196 | if (ftruncate(outfd, stat.st_size) != 0) | |
13ee9fdb | 197 | fail("Cannot truncate %s: %s\n", outfile, strerror(errno)); |
8512287a NL |
198 | |
199 | outbuf = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, | |
200 | outfd, 0); | |
201 | if (outbuf == MAP_FAILED) | |
13ee9fdb | 202 | fail("Failed to map %s: %s\n", outfile, strerror(errno)); |
8512287a NL |
203 | |
204 | close(outfd); | |
205 | ||
206 | memcpy(outbuf, inbuf, stat.st_size); | |
207 | ||
208 | if (clear_soft_float) { | |
209 | Elf32_Ehdr *outhdr; | |
210 | ||
211 | outhdr = outbuf; | |
212 | e_flags &= ~EF_ARM_ABI_FLOAT_SOFT; | |
213 | write_elf_word(e_flags, &outhdr->e_flags, swap); | |
214 | } | |
215 | ||
216 | if (msync(outbuf, stat.st_size, MS_SYNC) != 0) | |
13ee9fdb | 217 | fail("Failed to sync %s: %s\n", outfile, strerror(errno)); |
8512287a NL |
218 | |
219 | return EXIT_SUCCESS; | |
220 | } |