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