162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2015 Mentor Graphics Corporation. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * vdsomunge - Host program which produces a shared object 662306a36Sopenharmony_ci * architecturally specified to be usable by both soft- and hard-float 762306a36Sopenharmony_ci * programs. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * The Procedure Call Standard for the ARM Architecture (ARM IHI 1062306a36Sopenharmony_ci * 0042E) says: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * 6.4.1 VFP and Base Standard Compatibility 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Code compiled for the VFP calling standard is compatible with 1562306a36Sopenharmony_ci * the base standard (and vice-versa) if no floating-point or 1662306a36Sopenharmony_ci * containerized vector arguments or results are used. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * And ELF for the ARM Architecture (ARM IHI 0044E) (Table 4-2) says: 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * If both EF_ARM_ABI_FLOAT_XXXX bits are clear, conformance to the 2162306a36Sopenharmony_ci * base procedure-call standard is implied. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * The VDSO is built with -msoft-float, as with the rest of the ARM 2462306a36Sopenharmony_ci * kernel, and uses no floating point arguments or results. The build 2562306a36Sopenharmony_ci * process will produce a shared object that may or may not have the 2662306a36Sopenharmony_ci * EF_ARM_ABI_FLOAT_SOFT flag set (it seems to depend on the binutils 2762306a36Sopenharmony_ci * version; binutils starting with 2.24 appears to set it). The 2862306a36Sopenharmony_ci * EF_ARM_ABI_FLOAT_HARD flag should definitely not be set, and this 2962306a36Sopenharmony_ci * program will error out if it is. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * If the soft-float flag is set, this program clears it. That's all 3262306a36Sopenharmony_ci * it does. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <elf.h> 3662306a36Sopenharmony_ci#include <errno.h> 3762306a36Sopenharmony_ci#include <fcntl.h> 3862306a36Sopenharmony_ci#include <stdarg.h> 3962306a36Sopenharmony_ci#include <stdbool.h> 4062306a36Sopenharmony_ci#include <stdio.h> 4162306a36Sopenharmony_ci#include <stdlib.h> 4262306a36Sopenharmony_ci#include <string.h> 4362306a36Sopenharmony_ci#include <sys/mman.h> 4462306a36Sopenharmony_ci#include <sys/stat.h> 4562306a36Sopenharmony_ci#include <sys/types.h> 4662306a36Sopenharmony_ci#include <unistd.h> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define swab16(x) \ 4962306a36Sopenharmony_ci ((((x) & 0x00ff) << 8) | \ 5062306a36Sopenharmony_ci (((x) & 0xff00) >> 8)) 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define swab32(x) \ 5362306a36Sopenharmony_ci ((((x) & 0x000000ff) << 24) | \ 5462306a36Sopenharmony_ci (((x) & 0x0000ff00) << 8) | \ 5562306a36Sopenharmony_ci (((x) & 0x00ff0000) >> 8) | \ 5662306a36Sopenharmony_ci (((x) & 0xff000000) >> 24)) 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 5962306a36Sopenharmony_ci#define HOST_ORDER ELFDATA2LSB 6062306a36Sopenharmony_ci#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 6162306a36Sopenharmony_ci#define HOST_ORDER ELFDATA2MSB 6262306a36Sopenharmony_ci#endif 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* Some of the ELF constants we'd like to use were added to <elf.h> 6562306a36Sopenharmony_ci * relatively recently. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci#ifndef EF_ARM_EABI_VER5 6862306a36Sopenharmony_ci#define EF_ARM_EABI_VER5 0x05000000 6962306a36Sopenharmony_ci#endif 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#ifndef EF_ARM_ABI_FLOAT_SOFT 7262306a36Sopenharmony_ci#define EF_ARM_ABI_FLOAT_SOFT 0x200 7362306a36Sopenharmony_ci#endif 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#ifndef EF_ARM_ABI_FLOAT_HARD 7662306a36Sopenharmony_ci#define EF_ARM_ABI_FLOAT_HARD 0x400 7762306a36Sopenharmony_ci#endif 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic int failed; 8062306a36Sopenharmony_cistatic const char *argv0; 8162306a36Sopenharmony_cistatic const char *outfile; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic void fail(const char *fmt, ...) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci va_list ap; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci failed = 1; 8862306a36Sopenharmony_ci fprintf(stderr, "%s: ", argv0); 8962306a36Sopenharmony_ci va_start(ap, fmt); 9062306a36Sopenharmony_ci vfprintf(stderr, fmt, ap); 9162306a36Sopenharmony_ci va_end(ap); 9262306a36Sopenharmony_ci exit(EXIT_FAILURE); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic void cleanup(void) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci if (failed && outfile != NULL) 9862306a36Sopenharmony_ci unlink(outfile); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic Elf32_Word read_elf_word(Elf32_Word word, bool swap) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci return swap ? swab32(word) : word; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic Elf32_Half read_elf_half(Elf32_Half half, bool swap) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci return swap ? swab16(half) : half; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic void write_elf_word(Elf32_Word val, Elf32_Word *dst, bool swap) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci *dst = swap ? swab32(val) : val; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciint main(int argc, char **argv) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci const Elf32_Ehdr *inhdr; 11962306a36Sopenharmony_ci bool clear_soft_float; 12062306a36Sopenharmony_ci const char *infile; 12162306a36Sopenharmony_ci Elf32_Word e_flags; 12262306a36Sopenharmony_ci const void *inbuf; 12362306a36Sopenharmony_ci struct stat stat; 12462306a36Sopenharmony_ci void *outbuf; 12562306a36Sopenharmony_ci bool swap; 12662306a36Sopenharmony_ci int outfd; 12762306a36Sopenharmony_ci int infd; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci atexit(cleanup); 13062306a36Sopenharmony_ci argv0 = argv[0]; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (argc != 3) 13362306a36Sopenharmony_ci fail("Usage: %s [infile] [outfile]\n", argv[0]); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci infile = argv[1]; 13662306a36Sopenharmony_ci outfile = argv[2]; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci infd = open(infile, O_RDONLY); 13962306a36Sopenharmony_ci if (infd < 0) 14062306a36Sopenharmony_ci fail("Cannot open %s: %s\n", infile, strerror(errno)); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (fstat(infd, &stat) != 0) 14362306a36Sopenharmony_ci fail("Failed stat for %s: %s\n", infile, strerror(errno)); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci inbuf = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, infd, 0); 14662306a36Sopenharmony_ci if (inbuf == MAP_FAILED) 14762306a36Sopenharmony_ci fail("Failed to map %s: %s\n", infile, strerror(errno)); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci close(infd); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci inhdr = inbuf; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (memcmp(&inhdr->e_ident, ELFMAG, SELFMAG) != 0) 15462306a36Sopenharmony_ci fail("Not an ELF file\n"); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (inhdr->e_ident[EI_CLASS] != ELFCLASS32) 15762306a36Sopenharmony_ci fail("Unsupported ELF class\n"); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci swap = inhdr->e_ident[EI_DATA] != HOST_ORDER; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (read_elf_half(inhdr->e_type, swap) != ET_DYN) 16262306a36Sopenharmony_ci fail("Not a shared object\n"); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (read_elf_half(inhdr->e_machine, swap) != EM_ARM) 16562306a36Sopenharmony_ci fail("Unsupported architecture %#x\n", inhdr->e_machine); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci e_flags = read_elf_word(inhdr->e_flags, swap); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (EF_ARM_EABI_VERSION(e_flags) != EF_ARM_EABI_VER5) { 17062306a36Sopenharmony_ci fail("Unsupported EABI version %#x\n", 17162306a36Sopenharmony_ci EF_ARM_EABI_VERSION(e_flags)); 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (e_flags & EF_ARM_ABI_FLOAT_HARD) 17562306a36Sopenharmony_ci fail("Unexpected hard-float flag set in e_flags\n"); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci clear_soft_float = !!(e_flags & EF_ARM_ABI_FLOAT_SOFT); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci outfd = open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 18062306a36Sopenharmony_ci if (outfd < 0) 18162306a36Sopenharmony_ci fail("Cannot open %s: %s\n", outfile, strerror(errno)); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (ftruncate(outfd, stat.st_size) != 0) 18462306a36Sopenharmony_ci fail("Cannot truncate %s: %s\n", outfile, strerror(errno)); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci outbuf = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, 18762306a36Sopenharmony_ci outfd, 0); 18862306a36Sopenharmony_ci if (outbuf == MAP_FAILED) 18962306a36Sopenharmony_ci fail("Failed to map %s: %s\n", outfile, strerror(errno)); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci close(outfd); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci memcpy(outbuf, inbuf, stat.st_size); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (clear_soft_float) { 19662306a36Sopenharmony_ci Elf32_Ehdr *outhdr; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci outhdr = outbuf; 19962306a36Sopenharmony_ci e_flags &= ~EF_ARM_ABI_FLOAT_SOFT; 20062306a36Sopenharmony_ci write_elf_word(e_flags, &outhdr->e_flags, swap); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (msync(outbuf, stat.st_size, MS_SYNC) != 0) 20462306a36Sopenharmony_ci fail("Failed to sync %s: %s\n", outfile, strerror(errno)); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci return EXIT_SUCCESS; 20762306a36Sopenharmony_ci} 208