18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2015 Mentor Graphics Corporation. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * vdsomunge - Host program which produces a shared object 68c2ecf20Sopenharmony_ci * architecturally specified to be usable by both soft- and hard-float 78c2ecf20Sopenharmony_ci * programs. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * The Procedure Call Standard for the ARM Architecture (ARM IHI 108c2ecf20Sopenharmony_ci * 0042E) says: 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * 6.4.1 VFP and Base Standard Compatibility 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Code compiled for the VFP calling standard is compatible with 158c2ecf20Sopenharmony_ci * the base standard (and vice-versa) if no floating-point or 168c2ecf20Sopenharmony_ci * containerized vector arguments or results are used. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * And ELF for the ARM Architecture (ARM IHI 0044E) (Table 4-2) says: 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * If both EF_ARM_ABI_FLOAT_XXXX bits are clear, conformance to the 218c2ecf20Sopenharmony_ci * base procedure-call standard is implied. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * The VDSO is built with -msoft-float, as with the rest of the ARM 248c2ecf20Sopenharmony_ci * kernel, and uses no floating point arguments or results. The build 258c2ecf20Sopenharmony_ci * process will produce a shared object that may or may not have the 268c2ecf20Sopenharmony_ci * EF_ARM_ABI_FLOAT_SOFT flag set (it seems to depend on the binutils 278c2ecf20Sopenharmony_ci * version; binutils starting with 2.24 appears to set it). The 288c2ecf20Sopenharmony_ci * EF_ARM_ABI_FLOAT_HARD flag should definitely not be set, and this 298c2ecf20Sopenharmony_ci * program will error out if it is. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * If the soft-float flag is set, this program clears it. That's all 328c2ecf20Sopenharmony_ci * it does. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include <elf.h> 368c2ecf20Sopenharmony_ci#include <errno.h> 378c2ecf20Sopenharmony_ci#include <fcntl.h> 388c2ecf20Sopenharmony_ci#include <stdarg.h> 398c2ecf20Sopenharmony_ci#include <stdbool.h> 408c2ecf20Sopenharmony_ci#include <stdio.h> 418c2ecf20Sopenharmony_ci#include <stdlib.h> 428c2ecf20Sopenharmony_ci#include <string.h> 438c2ecf20Sopenharmony_ci#include <sys/mman.h> 448c2ecf20Sopenharmony_ci#include <sys/stat.h> 458c2ecf20Sopenharmony_ci#include <sys/types.h> 468c2ecf20Sopenharmony_ci#include <unistd.h> 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define swab16(x) \ 498c2ecf20Sopenharmony_ci ((((x) & 0x00ff) << 8) | \ 508c2ecf20Sopenharmony_ci (((x) & 0xff00) >> 8)) 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define swab32(x) \ 538c2ecf20Sopenharmony_ci ((((x) & 0x000000ff) << 24) | \ 548c2ecf20Sopenharmony_ci (((x) & 0x0000ff00) << 8) | \ 558c2ecf20Sopenharmony_ci (((x) & 0x00ff0000) >> 8) | \ 568c2ecf20Sopenharmony_ci (((x) & 0xff000000) >> 24)) 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 598c2ecf20Sopenharmony_ci#define HOST_ORDER ELFDATA2LSB 608c2ecf20Sopenharmony_ci#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 618c2ecf20Sopenharmony_ci#define HOST_ORDER ELFDATA2MSB 628c2ecf20Sopenharmony_ci#endif 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* Some of the ELF constants we'd like to use were added to <elf.h> 658c2ecf20Sopenharmony_ci * relatively recently. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci#ifndef EF_ARM_EABI_VER5 688c2ecf20Sopenharmony_ci#define EF_ARM_EABI_VER5 0x05000000 698c2ecf20Sopenharmony_ci#endif 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#ifndef EF_ARM_ABI_FLOAT_SOFT 728c2ecf20Sopenharmony_ci#define EF_ARM_ABI_FLOAT_SOFT 0x200 738c2ecf20Sopenharmony_ci#endif 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#ifndef EF_ARM_ABI_FLOAT_HARD 768c2ecf20Sopenharmony_ci#define EF_ARM_ABI_FLOAT_HARD 0x400 778c2ecf20Sopenharmony_ci#endif 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int failed; 808c2ecf20Sopenharmony_cistatic const char *argv0; 818c2ecf20Sopenharmony_cistatic const char *outfile; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic void fail(const char *fmt, ...) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci va_list ap; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci failed = 1; 888c2ecf20Sopenharmony_ci fprintf(stderr, "%s: ", argv0); 898c2ecf20Sopenharmony_ci va_start(ap, fmt); 908c2ecf20Sopenharmony_ci vfprintf(stderr, fmt, ap); 918c2ecf20Sopenharmony_ci va_end(ap); 928c2ecf20Sopenharmony_ci exit(EXIT_FAILURE); 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic void cleanup(void) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci if (failed && outfile != NULL) 988c2ecf20Sopenharmony_ci unlink(outfile); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic Elf32_Word read_elf_word(Elf32_Word word, bool swap) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci return swap ? swab32(word) : word; 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic Elf32_Half read_elf_half(Elf32_Half half, bool swap) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci return swap ? swab16(half) : half; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic void write_elf_word(Elf32_Word val, Elf32_Word *dst, bool swap) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci *dst = swap ? swab32(val) : val; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ciint main(int argc, char **argv) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci const Elf32_Ehdr *inhdr; 1198c2ecf20Sopenharmony_ci bool clear_soft_float; 1208c2ecf20Sopenharmony_ci const char *infile; 1218c2ecf20Sopenharmony_ci Elf32_Word e_flags; 1228c2ecf20Sopenharmony_ci const void *inbuf; 1238c2ecf20Sopenharmony_ci struct stat stat; 1248c2ecf20Sopenharmony_ci void *outbuf; 1258c2ecf20Sopenharmony_ci bool swap; 1268c2ecf20Sopenharmony_ci int outfd; 1278c2ecf20Sopenharmony_ci int infd; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci atexit(cleanup); 1308c2ecf20Sopenharmony_ci argv0 = argv[0]; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (argc != 3) 1338c2ecf20Sopenharmony_ci fail("Usage: %s [infile] [outfile]\n", argv[0]); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci infile = argv[1]; 1368c2ecf20Sopenharmony_ci outfile = argv[2]; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci infd = open(infile, O_RDONLY); 1398c2ecf20Sopenharmony_ci if (infd < 0) 1408c2ecf20Sopenharmony_ci fail("Cannot open %s: %s\n", infile, strerror(errno)); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (fstat(infd, &stat) != 0) 1438c2ecf20Sopenharmony_ci fail("Failed stat for %s: %s\n", infile, strerror(errno)); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci inbuf = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, infd, 0); 1468c2ecf20Sopenharmony_ci if (inbuf == MAP_FAILED) 1478c2ecf20Sopenharmony_ci fail("Failed to map %s: %s\n", infile, strerror(errno)); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci close(infd); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci inhdr = inbuf; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (memcmp(&inhdr->e_ident, ELFMAG, SELFMAG) != 0) 1548c2ecf20Sopenharmony_ci fail("Not an ELF file\n"); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (inhdr->e_ident[EI_CLASS] != ELFCLASS32) 1578c2ecf20Sopenharmony_ci fail("Unsupported ELF class\n"); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci swap = inhdr->e_ident[EI_DATA] != HOST_ORDER; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci if (read_elf_half(inhdr->e_type, swap) != ET_DYN) 1628c2ecf20Sopenharmony_ci fail("Not a shared object\n"); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (read_elf_half(inhdr->e_machine, swap) != EM_ARM) 1658c2ecf20Sopenharmony_ci fail("Unsupported architecture %#x\n", inhdr->e_machine); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci e_flags = read_elf_word(inhdr->e_flags, swap); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (EF_ARM_EABI_VERSION(e_flags) != EF_ARM_EABI_VER5) { 1708c2ecf20Sopenharmony_ci fail("Unsupported EABI version %#x\n", 1718c2ecf20Sopenharmony_ci EF_ARM_EABI_VERSION(e_flags)); 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (e_flags & EF_ARM_ABI_FLOAT_HARD) 1758c2ecf20Sopenharmony_ci fail("Unexpected hard-float flag set in e_flags\n"); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci clear_soft_float = !!(e_flags & EF_ARM_ABI_FLOAT_SOFT); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci outfd = open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 1808c2ecf20Sopenharmony_ci if (outfd < 0) 1818c2ecf20Sopenharmony_ci fail("Cannot open %s: %s\n", outfile, strerror(errno)); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (ftruncate(outfd, stat.st_size) != 0) 1848c2ecf20Sopenharmony_ci fail("Cannot truncate %s: %s\n", outfile, strerror(errno)); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci outbuf = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, 1878c2ecf20Sopenharmony_ci outfd, 0); 1888c2ecf20Sopenharmony_ci if (outbuf == MAP_FAILED) 1898c2ecf20Sopenharmony_ci fail("Failed to map %s: %s\n", outfile, strerror(errno)); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci close(outfd); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci memcpy(outbuf, inbuf, stat.st_size); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (clear_soft_float) { 1968c2ecf20Sopenharmony_ci Elf32_Ehdr *outhdr; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci outhdr = outbuf; 1998c2ecf20Sopenharmony_ci e_flags &= ~EF_ARM_ABI_FLOAT_SOFT; 2008c2ecf20Sopenharmony_ci write_elf_word(e_flags, &outhdr->e_flags, swap); 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (msync(outbuf, stat.st_size, MS_SYNC) != 0) 2048c2ecf20Sopenharmony_ci fail("Failed to sync %s: %s\n", outfile, strerror(errno)); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return EXIT_SUCCESS; 2078c2ecf20Sopenharmony_ci} 208