forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
5.0 KiB
207 lines
5.0 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* |
|
* Copyright 2015 Mentor Graphics Corporation. |
|
* |
|
* vdsomunge - Host program which produces a shared object |
|
* architecturally specified to be usable by both soft- and hard-float |
|
* programs. |
|
* |
|
* The Procedure Call Standard for the ARM Architecture (ARM IHI |
|
* 0042E) says: |
|
* |
|
* 6.4.1 VFP and Base Standard Compatibility |
|
* |
|
* Code compiled for the VFP calling standard is compatible with |
|
* the base standard (and vice-versa) if no floating-point or |
|
* containerized vector arguments or results are used. |
|
* |
|
* And ELF for the ARM Architecture (ARM IHI 0044E) (Table 4-2) says: |
|
* |
|
* If both EF_ARM_ABI_FLOAT_XXXX bits are clear, conformance to the |
|
* base procedure-call standard is implied. |
|
* |
|
* The VDSO is built with -msoft-float, as with the rest of the ARM |
|
* kernel, and uses no floating point arguments or results. The build |
|
* process will produce a shared object that may or may not have the |
|
* EF_ARM_ABI_FLOAT_SOFT flag set (it seems to depend on the binutils |
|
* version; binutils starting with 2.24 appears to set it). The |
|
* EF_ARM_ABI_FLOAT_HARD flag should definitely not be set, and this |
|
* program will error out if it is. |
|
* |
|
* If the soft-float flag is set, this program clears it. That's all |
|
* it does. |
|
*/ |
|
|
|
#include <elf.h> |
|
#include <errno.h> |
|
#include <fcntl.h> |
|
#include <stdarg.h> |
|
#include <stdbool.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <sys/mman.h> |
|
#include <sys/stat.h> |
|
#include <sys/types.h> |
|
#include <unistd.h> |
|
|
|
#define swab16(x) \ |
|
((((x) & 0x00ff) << 8) | \ |
|
(((x) & 0xff00) >> 8)) |
|
|
|
#define swab32(x) \ |
|
((((x) & 0x000000ff) << 24) | \ |
|
(((x) & 0x0000ff00) << 8) | \ |
|
(((x) & 0x00ff0000) >> 8) | \ |
|
(((x) & 0xff000000) >> 24)) |
|
|
|
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ |
|
#define HOST_ORDER ELFDATA2LSB |
|
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ |
|
#define HOST_ORDER ELFDATA2MSB |
|
#endif |
|
|
|
/* Some of the ELF constants we'd like to use were added to <elf.h> |
|
* relatively recently. |
|
*/ |
|
#ifndef EF_ARM_EABI_VER5 |
|
#define EF_ARM_EABI_VER5 0x05000000 |
|
#endif |
|
|
|
#ifndef EF_ARM_ABI_FLOAT_SOFT |
|
#define EF_ARM_ABI_FLOAT_SOFT 0x200 |
|
#endif |
|
|
|
#ifndef EF_ARM_ABI_FLOAT_HARD |
|
#define EF_ARM_ABI_FLOAT_HARD 0x400 |
|
#endif |
|
|
|
static int failed; |
|
static const char *argv0; |
|
static const char *outfile; |
|
|
|
static void fail(const char *fmt, ...) |
|
{ |
|
va_list ap; |
|
|
|
failed = 1; |
|
fprintf(stderr, "%s: ", argv0); |
|
va_start(ap, fmt); |
|
vfprintf(stderr, fmt, ap); |
|
va_end(ap); |
|
exit(EXIT_FAILURE); |
|
} |
|
|
|
static void cleanup(void) |
|
{ |
|
if (failed && outfile != NULL) |
|
unlink(outfile); |
|
} |
|
|
|
static Elf32_Word read_elf_word(Elf32_Word word, bool swap) |
|
{ |
|
return swap ? swab32(word) : word; |
|
} |
|
|
|
static Elf32_Half read_elf_half(Elf32_Half half, bool swap) |
|
{ |
|
return swap ? swab16(half) : half; |
|
} |
|
|
|
static void write_elf_word(Elf32_Word val, Elf32_Word *dst, bool swap) |
|
{ |
|
*dst = swap ? swab32(val) : val; |
|
} |
|
|
|
int main(int argc, char **argv) |
|
{ |
|
const Elf32_Ehdr *inhdr; |
|
bool clear_soft_float; |
|
const char *infile; |
|
Elf32_Word e_flags; |
|
const void *inbuf; |
|
struct stat stat; |
|
void *outbuf; |
|
bool swap; |
|
int outfd; |
|
int infd; |
|
|
|
atexit(cleanup); |
|
argv0 = argv[0]; |
|
|
|
if (argc != 3) |
|
fail("Usage: %s [infile] [outfile]\n", argv[0]); |
|
|
|
infile = argv[1]; |
|
outfile = argv[2]; |
|
|
|
infd = open(infile, O_RDONLY); |
|
if (infd < 0) |
|
fail("Cannot open %s: %s\n", infile, strerror(errno)); |
|
|
|
if (fstat(infd, &stat) != 0) |
|
fail("Failed stat for %s: %s\n", infile, strerror(errno)); |
|
|
|
inbuf = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, infd, 0); |
|
if (inbuf == MAP_FAILED) |
|
fail("Failed to map %s: %s\n", infile, strerror(errno)); |
|
|
|
close(infd); |
|
|
|
inhdr = inbuf; |
|
|
|
if (memcmp(&inhdr->e_ident, ELFMAG, SELFMAG) != 0) |
|
fail("Not an ELF file\n"); |
|
|
|
if (inhdr->e_ident[EI_CLASS] != ELFCLASS32) |
|
fail("Unsupported ELF class\n"); |
|
|
|
swap = inhdr->e_ident[EI_DATA] != HOST_ORDER; |
|
|
|
if (read_elf_half(inhdr->e_type, swap) != ET_DYN) |
|
fail("Not a shared object\n"); |
|
|
|
if (read_elf_half(inhdr->e_machine, swap) != EM_ARM) |
|
fail("Unsupported architecture %#x\n", inhdr->e_machine); |
|
|
|
e_flags = read_elf_word(inhdr->e_flags, swap); |
|
|
|
if (EF_ARM_EABI_VERSION(e_flags) != EF_ARM_EABI_VER5) { |
|
fail("Unsupported EABI version %#x\n", |
|
EF_ARM_EABI_VERSION(e_flags)); |
|
} |
|
|
|
if (e_flags & EF_ARM_ABI_FLOAT_HARD) |
|
fail("Unexpected hard-float flag set in e_flags\n"); |
|
|
|
clear_soft_float = !!(e_flags & EF_ARM_ABI_FLOAT_SOFT); |
|
|
|
outfd = open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); |
|
if (outfd < 0) |
|
fail("Cannot open %s: %s\n", outfile, strerror(errno)); |
|
|
|
if (ftruncate(outfd, stat.st_size) != 0) |
|
fail("Cannot truncate %s: %s\n", outfile, strerror(errno)); |
|
|
|
outbuf = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, |
|
outfd, 0); |
|
if (outbuf == MAP_FAILED) |
|
fail("Failed to map %s: %s\n", outfile, strerror(errno)); |
|
|
|
close(outfd); |
|
|
|
memcpy(outbuf, inbuf, stat.st_size); |
|
|
|
if (clear_soft_float) { |
|
Elf32_Ehdr *outhdr; |
|
|
|
outhdr = outbuf; |
|
e_flags &= ~EF_ARM_ABI_FLOAT_SOFT; |
|
write_elf_word(e_flags, &outhdr->e_flags, swap); |
|
} |
|
|
|
if (msync(outbuf, stat.st_size, MS_SYNC) != 0) |
|
fail("Failed to sync %s: %s\n", outfile, strerror(errno)); |
|
|
|
return EXIT_SUCCESS; |
|
}
|
|
|