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