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 48 #define _GNU_SOURCE 49 50 #include <byteswap.h> 51 #include <elf.h> 52 #include <errno.h> 53 #include <error.h> 54 #include <fcntl.h> 55 #include <stdbool.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <sys/mman.h> 60 #include <sys/stat.h> 61 #include <sys/types.h> 62 #include <unistd.h> 63 64 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 65 #define HOST_ORDER ELFDATA2LSB 66 #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 67 #define HOST_ORDER ELFDATA2MSB 68 #endif 69 70 /* Some of the ELF constants we'd like to use were added to <elf.h> 71 * relatively recently. 72 */ 73 #ifndef EF_ARM_EABI_VER5 74 #define EF_ARM_EABI_VER5 0x05000000 75 #endif 76 77 #ifndef EF_ARM_ABI_FLOAT_SOFT 78 #define EF_ARM_ABI_FLOAT_SOFT 0x200 79 #endif 80 81 #ifndef EF_ARM_ABI_FLOAT_HARD 82 #define EF_ARM_ABI_FLOAT_HARD 0x400 83 #endif 84 85 static const char *outfile; 86 87 static void cleanup(void) 88 { 89 if (error_message_count > 0 && outfile != NULL) 90 unlink(outfile); 91 } 92 93 static Elf32_Word read_elf_word(Elf32_Word word, bool swap) 94 { 95 return swap ? bswap_32(word) : word; 96 } 97 98 static Elf32_Half read_elf_half(Elf32_Half half, bool swap) 99 { 100 return swap ? bswap_16(half) : half; 101 } 102 103 static void write_elf_word(Elf32_Word val, Elf32_Word *dst, bool swap) 104 { 105 *dst = swap ? bswap_32(val) : val; 106 } 107 108 int main(int argc, char **argv) 109 { 110 const Elf32_Ehdr *inhdr; 111 bool clear_soft_float; 112 const char *infile; 113 Elf32_Word e_flags; 114 const void *inbuf; 115 struct stat stat; 116 void *outbuf; 117 bool swap; 118 int outfd; 119 int infd; 120 121 atexit(cleanup); 122 123 if (argc != 3) 124 error(EXIT_FAILURE, 0, "Usage: %s [infile] [outfile]", argv[0]); 125 126 infile = argv[1]; 127 outfile = argv[2]; 128 129 infd = open(infile, O_RDONLY); 130 if (infd < 0) 131 error(EXIT_FAILURE, errno, "Cannot open %s", infile); 132 133 if (fstat(infd, &stat) != 0) 134 error(EXIT_FAILURE, errno, "Failed stat for %s", infile); 135 136 inbuf = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, infd, 0); 137 if (inbuf == MAP_FAILED) 138 error(EXIT_FAILURE, errno, "Failed to map %s", infile); 139 140 close(infd); 141 142 inhdr = inbuf; 143 144 if (memcmp(&inhdr->e_ident, ELFMAG, SELFMAG) != 0) 145 error(EXIT_FAILURE, 0, "Not an ELF file"); 146 147 if (inhdr->e_ident[EI_CLASS] != ELFCLASS32) 148 error(EXIT_FAILURE, 0, "Unsupported ELF class"); 149 150 swap = inhdr->e_ident[EI_DATA] != HOST_ORDER; 151 152 if (read_elf_half(inhdr->e_type, swap) != ET_DYN) 153 error(EXIT_FAILURE, 0, "Not a shared object"); 154 155 if (read_elf_half(inhdr->e_machine, swap) != EM_ARM) { 156 error(EXIT_FAILURE, 0, "Unsupported architecture %#x", 157 inhdr->e_machine); 158 } 159 160 e_flags = read_elf_word(inhdr->e_flags, swap); 161 162 if (EF_ARM_EABI_VERSION(e_flags) != EF_ARM_EABI_VER5) { 163 error(EXIT_FAILURE, 0, "Unsupported EABI version %#x", 164 EF_ARM_EABI_VERSION(e_flags)); 165 } 166 167 if (e_flags & EF_ARM_ABI_FLOAT_HARD) 168 error(EXIT_FAILURE, 0, 169 "Unexpected hard-float flag set in e_flags"); 170 171 clear_soft_float = !!(e_flags & EF_ARM_ABI_FLOAT_SOFT); 172 173 outfd = open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 174 if (outfd < 0) 175 error(EXIT_FAILURE, errno, "Cannot open %s", outfile); 176 177 if (ftruncate(outfd, stat.st_size) != 0) 178 error(EXIT_FAILURE, errno, "Cannot truncate %s", outfile); 179 180 outbuf = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, 181 outfd, 0); 182 if (outbuf == MAP_FAILED) 183 error(EXIT_FAILURE, errno, "Failed to map %s", outfile); 184 185 close(outfd); 186 187 memcpy(outbuf, inbuf, stat.st_size); 188 189 if (clear_soft_float) { 190 Elf32_Ehdr *outhdr; 191 192 outhdr = outbuf; 193 e_flags &= ~EF_ARM_ABI_FLOAT_SOFT; 194 write_elf_word(e_flags, &outhdr->e_flags, swap); 195 } 196 197 if (msync(outbuf, stat.st_size, MS_SYNC) != 0) 198 error(EXIT_FAILURE, errno, "Failed to sync %s", outfile); 199 200 return EXIT_SUCCESS; 201 } 202