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