linux-user: Add gen-vdso tool
This tool will be used for post-processing the linked vdso image, turning it into something that is easy to include into elfload.c. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
c40f621a19
commit
2fa536d107
307
linux-user/gen-vdso-elfn.c.inc
Normal file
307
linux-user/gen-vdso-elfn.c.inc
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
/*
|
||||||
|
* Post-process a vdso elf image for inclusion into qemu.
|
||||||
|
* Elf size specialization.
|
||||||
|
*
|
||||||
|
* Copyright 2023 Linaro, Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void elfN(bswap_ehdr)(ElfN(Ehdr) *ehdr)
|
||||||
|
{
|
||||||
|
bswaps(&ehdr->e_type); /* Object file type */
|
||||||
|
bswaps(&ehdr->e_machine); /* Architecture */
|
||||||
|
bswaps(&ehdr->e_version); /* Object file version */
|
||||||
|
bswaps(&ehdr->e_entry); /* Entry point virtual address */
|
||||||
|
bswaps(&ehdr->e_phoff); /* Program header table file offset */
|
||||||
|
bswaps(&ehdr->e_shoff); /* Section header table file offset */
|
||||||
|
bswaps(&ehdr->e_flags); /* Processor-specific flags */
|
||||||
|
bswaps(&ehdr->e_ehsize); /* ELF header size in bytes */
|
||||||
|
bswaps(&ehdr->e_phentsize); /* Program header table entry size */
|
||||||
|
bswaps(&ehdr->e_phnum); /* Program header table entry count */
|
||||||
|
bswaps(&ehdr->e_shentsize); /* Section header table entry size */
|
||||||
|
bswaps(&ehdr->e_shnum); /* Section header table entry count */
|
||||||
|
bswaps(&ehdr->e_shstrndx); /* Section header string table index */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elfN(bswap_phdr)(ElfN(Phdr) *phdr)
|
||||||
|
{
|
||||||
|
bswaps(&phdr->p_type); /* Segment type */
|
||||||
|
bswaps(&phdr->p_flags); /* Segment flags */
|
||||||
|
bswaps(&phdr->p_offset); /* Segment file offset */
|
||||||
|
bswaps(&phdr->p_vaddr); /* Segment virtual address */
|
||||||
|
bswaps(&phdr->p_paddr); /* Segment physical address */
|
||||||
|
bswaps(&phdr->p_filesz); /* Segment size in file */
|
||||||
|
bswaps(&phdr->p_memsz); /* Segment size in memory */
|
||||||
|
bswaps(&phdr->p_align); /* Segment alignment */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elfN(bswap_shdr)(ElfN(Shdr) *shdr)
|
||||||
|
{
|
||||||
|
bswaps(&shdr->sh_name);
|
||||||
|
bswaps(&shdr->sh_type);
|
||||||
|
bswaps(&shdr->sh_flags);
|
||||||
|
bswaps(&shdr->sh_addr);
|
||||||
|
bswaps(&shdr->sh_offset);
|
||||||
|
bswaps(&shdr->sh_size);
|
||||||
|
bswaps(&shdr->sh_link);
|
||||||
|
bswaps(&shdr->sh_info);
|
||||||
|
bswaps(&shdr->sh_addralign);
|
||||||
|
bswaps(&shdr->sh_entsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elfN(bswap_sym)(ElfN(Sym) *sym)
|
||||||
|
{
|
||||||
|
bswaps(&sym->st_name);
|
||||||
|
bswaps(&sym->st_value);
|
||||||
|
bswaps(&sym->st_size);
|
||||||
|
bswaps(&sym->st_shndx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elfN(bswap_dyn)(ElfN(Dyn) *dyn)
|
||||||
|
{
|
||||||
|
bswaps(&dyn->d_tag); /* Dynamic type tag */
|
||||||
|
bswaps(&dyn->d_un.d_ptr); /* Dynamic ptr or val, in union */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elfN(search_symtab)(ElfN(Shdr) *shdr, unsigned sym_idx,
|
||||||
|
void *buf, bool need_bswap)
|
||||||
|
{
|
||||||
|
unsigned str_idx = shdr[sym_idx].sh_link;
|
||||||
|
ElfN(Sym) *sym = buf + shdr[sym_idx].sh_offset;
|
||||||
|
unsigned sym_n = shdr[sym_idx].sh_size / sizeof(*sym);
|
||||||
|
const char *str = buf + shdr[str_idx].sh_offset;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < sym_n; ++i) {
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
if (need_bswap) {
|
||||||
|
elfN(bswap_sym)(sym + i);
|
||||||
|
}
|
||||||
|
name = str + sym[i].st_name;
|
||||||
|
|
||||||
|
if (sigreturn_sym && strcmp(sigreturn_sym, name) == 0) {
|
||||||
|
sigreturn_addr = sym[i].st_value;
|
||||||
|
}
|
||||||
|
if (rt_sigreturn_sym && strcmp(rt_sigreturn_sym, name) == 0) {
|
||||||
|
rt_sigreturn_addr = sym[i].st_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void elfN(process)(FILE *outf, void *buf, bool need_bswap)
|
||||||
|
{
|
||||||
|
ElfN(Ehdr) *ehdr = buf;
|
||||||
|
ElfN(Phdr) *phdr;
|
||||||
|
ElfN(Shdr) *shdr;
|
||||||
|
unsigned phnum, shnum;
|
||||||
|
unsigned dynamic_ofs = 0;
|
||||||
|
unsigned dynamic_addr = 0;
|
||||||
|
unsigned symtab_idx = 0;
|
||||||
|
unsigned dynsym_idx = 0;
|
||||||
|
unsigned first_segsz = 0;
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
if (need_bswap) {
|
||||||
|
elfN(bswap_ehdr)(ehdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
phnum = ehdr->e_phnum;
|
||||||
|
phdr = buf + ehdr->e_phoff;
|
||||||
|
if (need_bswap) {
|
||||||
|
for (unsigned i = 0; i < phnum; ++i) {
|
||||||
|
elfN(bswap_phdr)(phdr + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shnum = ehdr->e_shnum;
|
||||||
|
shdr = buf + ehdr->e_shoff;
|
||||||
|
if (need_bswap) {
|
||||||
|
for (unsigned i = 0; i < shnum; ++i) {
|
||||||
|
elfN(bswap_shdr)(shdr + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < shnum; ++i) {
|
||||||
|
switch (shdr[i].sh_type) {
|
||||||
|
case SHT_SYMTAB:
|
||||||
|
symtab_idx = i;
|
||||||
|
break;
|
||||||
|
case SHT_DYNSYM:
|
||||||
|
dynsym_idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate the VDSO is created as we expect: that PT_PHDR,
|
||||||
|
* PT_DYNAMIC, and PT_NOTE located in a writable data segment.
|
||||||
|
* PHDR and DYNAMIC require relocation, and NOTE will get the
|
||||||
|
* linux version number.
|
||||||
|
*/
|
||||||
|
for (unsigned i = 0; i < phnum; ++i) {
|
||||||
|
if (phdr[i].p_type != PT_LOAD) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (first_segsz != 0) {
|
||||||
|
fprintf(stderr, "Multiple LOAD segments\n");
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
if (phdr[i].p_offset != 0) {
|
||||||
|
fprintf(stderr, "LOAD segment does not cover EHDR\n");
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
if (phdr[i].p_vaddr != 0) {
|
||||||
|
fprintf(stderr, "LOAD segment not loaded at address 0\n");
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
first_segsz = phdr[i].p_filesz;
|
||||||
|
if (first_segsz < ehdr->e_phoff + phnum * sizeof(*phdr)) {
|
||||||
|
fprintf(stderr, "LOAD segment does not cover PHDRs\n");
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
if ((phdr[i].p_flags & (PF_R | PF_W)) != (PF_R | PF_W)) {
|
||||||
|
fprintf(stderr, "LOAD segment is not read-write\n");
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < phnum; ++i) {
|
||||||
|
const char *which;
|
||||||
|
|
||||||
|
switch (phdr[i].p_type) {
|
||||||
|
case PT_PHDR:
|
||||||
|
which = "PT_PHDR";
|
||||||
|
break;
|
||||||
|
case PT_NOTE:
|
||||||
|
which = "PT_NOTE";
|
||||||
|
break;
|
||||||
|
case PT_DYNAMIC:
|
||||||
|
dynamic_ofs = phdr[i].p_offset;
|
||||||
|
dynamic_addr = phdr[i].p_vaddr;
|
||||||
|
which = "PT_DYNAMIC";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (first_segsz < phdr[i].p_vaddr + phdr[i].p_filesz) {
|
||||||
|
fprintf(stderr, "LOAD segment does not cover %s\n", which);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errors) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Relocate the program headers. */
|
||||||
|
for (unsigned i = 0; i < phnum; ++i) {
|
||||||
|
output_reloc(outf, buf, &phdr[i].p_vaddr);
|
||||||
|
output_reloc(outf, buf, &phdr[i].p_paddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Relocate the DYNAMIC entries. */
|
||||||
|
if (dynamic_addr) {
|
||||||
|
ElfN(Dyn) *dyn = buf + dynamic_ofs;
|
||||||
|
__typeof(dyn->d_tag) tag;
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
if (need_bswap) {
|
||||||
|
elfN(bswap_dyn)(dyn);
|
||||||
|
}
|
||||||
|
tag = dyn->d_tag;
|
||||||
|
|
||||||
|
switch (tag) {
|
||||||
|
case DT_HASH:
|
||||||
|
case DT_SYMTAB:
|
||||||
|
case DT_STRTAB:
|
||||||
|
case DT_VERDEF:
|
||||||
|
case DT_VERSYM:
|
||||||
|
case DT_PLTGOT:
|
||||||
|
case DT_ADDRRNGLO ... DT_ADDRRNGHI:
|
||||||
|
/* These entries store an address in the entry. */
|
||||||
|
output_reloc(outf, buf, &dyn->d_un.d_val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DT_NULL:
|
||||||
|
case DT_STRSZ:
|
||||||
|
case DT_SONAME:
|
||||||
|
case DT_DEBUG:
|
||||||
|
case DT_FLAGS:
|
||||||
|
case DT_FLAGS_1:
|
||||||
|
case DT_SYMBOLIC:
|
||||||
|
case DT_BIND_NOW:
|
||||||
|
case DT_VERDEFNUM:
|
||||||
|
case DT_VALRNGLO ... DT_VALRNGHI:
|
||||||
|
/* These entries store an integer in the entry. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DT_SYMENT:
|
||||||
|
if (dyn->d_un.d_val != sizeof(ElfN(Sym))) {
|
||||||
|
fprintf(stderr, "VDSO has incorrect dynamic symbol size\n");
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DT_REL:
|
||||||
|
case DT_RELSZ:
|
||||||
|
case DT_RELA:
|
||||||
|
case DT_RELASZ:
|
||||||
|
/*
|
||||||
|
* These entries indicate that the VDSO was built incorrectly.
|
||||||
|
* It should not have any real relocations.
|
||||||
|
* ??? The RISC-V toolchain will emit these even when there
|
||||||
|
* are no relocations. Validate zeros.
|
||||||
|
*/
|
||||||
|
if (dyn->d_un.d_val != 0) {
|
||||||
|
fprintf(stderr, "VDSO has dynamic relocations\n");
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DT_RELENT:
|
||||||
|
case DT_RELAENT:
|
||||||
|
case DT_TEXTREL:
|
||||||
|
/* These entries store an integer in the entry. */
|
||||||
|
/* Should not be required; see above. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DT_NEEDED:
|
||||||
|
case DT_VERNEED:
|
||||||
|
case DT_PLTREL:
|
||||||
|
case DT_JMPREL:
|
||||||
|
case DT_RPATH:
|
||||||
|
case DT_RUNPATH:
|
||||||
|
fprintf(stderr, "VDSO has external dependencies\n");
|
||||||
|
errors++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* This is probably something target specific. */
|
||||||
|
fprintf(stderr, "VDSO has unknown DYNAMIC entry (%lx)\n",
|
||||||
|
(unsigned long)tag);
|
||||||
|
errors++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dyn++;
|
||||||
|
} while (tag != DT_NULL);
|
||||||
|
if (errors) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Relocate the dynamic symbol table. */
|
||||||
|
if (dynsym_idx) {
|
||||||
|
ElfN(Sym) *sym = buf + shdr[dynsym_idx].sh_offset;
|
||||||
|
unsigned sym_n = shdr[dynsym_idx].sh_size / sizeof(*sym);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < sym_n; ++i) {
|
||||||
|
output_reloc(outf, buf, &sym[i].st_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search both dynsym and symtab for the signal return symbols. */
|
||||||
|
if (dynsym_idx) {
|
||||||
|
elfN(search_symtab)(shdr, dynsym_idx, buf, need_bswap);
|
||||||
|
}
|
||||||
|
if (symtab_idx) {
|
||||||
|
elfN(search_symtab)(shdr, symtab_idx, buf, need_bswap);
|
||||||
|
}
|
||||||
|
}
|
223
linux-user/gen-vdso.c
Normal file
223
linux-user/gen-vdso.c
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
* Post-process a vdso elf image for inclusion into qemu.
|
||||||
|
*
|
||||||
|
* Copyright 2023 Linaro, Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <endian.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "elf.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define bswap_(p) _Generic(*(p), \
|
||||||
|
uint16_t: __builtin_bswap16, \
|
||||||
|
uint32_t: __builtin_bswap32, \
|
||||||
|
uint64_t: __builtin_bswap64, \
|
||||||
|
int16_t: __builtin_bswap16, \
|
||||||
|
int32_t: __builtin_bswap32, \
|
||||||
|
int64_t: __builtin_bswap64)
|
||||||
|
#define bswaps(p) (*(p) = bswap_(p)(*(p)))
|
||||||
|
|
||||||
|
static void output_reloc(FILE *outf, void *buf, void *loc)
|
||||||
|
{
|
||||||
|
fprintf(outf, " 0x%08tx,\n", loc - buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *sigreturn_sym;
|
||||||
|
static const char *rt_sigreturn_sym;
|
||||||
|
|
||||||
|
static unsigned sigreturn_addr;
|
||||||
|
static unsigned rt_sigreturn_addr;
|
||||||
|
|
||||||
|
#define N 32
|
||||||
|
#define elfN(x) elf32_##x
|
||||||
|
#define ElfN(x) Elf32_##x
|
||||||
|
#include "gen-vdso-elfn.c.inc"
|
||||||
|
#undef N
|
||||||
|
#undef elfN
|
||||||
|
#undef ElfN
|
||||||
|
|
||||||
|
#define N 64
|
||||||
|
#define elfN(x) elf64_##x
|
||||||
|
#define ElfN(x) Elf64_##x
|
||||||
|
#include "gen-vdso-elfn.c.inc"
|
||||||
|
#undef N
|
||||||
|
#undef elfN
|
||||||
|
#undef ElfN
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
FILE *inf, *outf;
|
||||||
|
long total_len;
|
||||||
|
const char *prefix = "vdso";
|
||||||
|
const char *inf_name;
|
||||||
|
const char *outf_name = NULL;
|
||||||
|
unsigned char *buf;
|
||||||
|
bool need_bswap;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int opt = getopt(argc, argv, "o:p:r:s:");
|
||||||
|
if (opt < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (opt) {
|
||||||
|
case 'o':
|
||||||
|
outf_name = optarg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
prefix = optarg;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
rt_sigreturn_sym = optarg;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
sigreturn_sym = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage:
|
||||||
|
fprintf(stderr, "usage: [-p prefix] [-r rt-sigreturn-name] "
|
||||||
|
"[-s sigreturn-name] -o output-file input-file\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind >= argc || outf_name == NULL) {
|
||||||
|
goto usage;
|
||||||
|
}
|
||||||
|
inf_name = argv[optind];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open the input and output files.
|
||||||
|
*/
|
||||||
|
inf = fopen(inf_name, "rb");
|
||||||
|
if (inf == NULL) {
|
||||||
|
goto perror_inf;
|
||||||
|
}
|
||||||
|
outf = fopen(outf_name, "w");
|
||||||
|
if (outf == NULL) {
|
||||||
|
goto perror_outf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the input file into a buffer.
|
||||||
|
* We expect the vdso to be small, on the order of one page,
|
||||||
|
* therefore we do not expect a partial read.
|
||||||
|
*/
|
||||||
|
fseek(inf, 0, SEEK_END);
|
||||||
|
total_len = ftell(inf);
|
||||||
|
fseek(inf, 0, SEEK_SET);
|
||||||
|
|
||||||
|
buf = malloc(total_len);
|
||||||
|
if (buf == NULL) {
|
||||||
|
goto perror_inf;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
if (fread(buf, 1, total_len, inf) != total_len) {
|
||||||
|
if (errno) {
|
||||||
|
goto perror_inf;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "%s: incomplete read\n", inf_name);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
fclose(inf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write out the vdso image now, before we make local changes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fprintf(outf,
|
||||||
|
"/* Automatically generated from linux-user/gen-vdso.c. */\n"
|
||||||
|
"\n"
|
||||||
|
"static const uint8_t %s_image[] = {",
|
||||||
|
prefix);
|
||||||
|
for (long i = 0; i < total_len; ++i) {
|
||||||
|
if (i % 12 == 0) {
|
||||||
|
fputs("\n ", outf);
|
||||||
|
}
|
||||||
|
fprintf(outf, " 0x%02x,", buf[i]);
|
||||||
|
}
|
||||||
|
fprintf(outf, "\n};\n\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Identify which elf flavor we're processing.
|
||||||
|
* The first 16 bytes of the file are e_ident.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (buf[EI_MAG0] != ELFMAG0 || buf[EI_MAG1] != ELFMAG1 ||
|
||||||
|
buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) {
|
||||||
|
fprintf(stderr, "%s: not an elf file\n", inf_name);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
switch (buf[EI_DATA]) {
|
||||||
|
case ELFDATA2LSB:
|
||||||
|
need_bswap = BYTE_ORDER != LITTLE_ENDIAN;
|
||||||
|
break;
|
||||||
|
case ELFDATA2MSB:
|
||||||
|
need_bswap = BYTE_ORDER != BIG_ENDIAN;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "%s: invalid elf EI_DATA (%u)\n",
|
||||||
|
inf_name, buf[EI_DATA]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to relocate the VDSO image. The one built into the kernel
|
||||||
|
* is built for a fixed address. The one we built for QEMU is not,
|
||||||
|
* since that requires close control of the guest address space.
|
||||||
|
*
|
||||||
|
* Output relocation addresses as we go.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fprintf(outf, "static const unsigned %s_relocs[] = {\n", prefix);
|
||||||
|
|
||||||
|
switch (buf[EI_CLASS]) {
|
||||||
|
case ELFCLASS32:
|
||||||
|
elf32_process(outf, buf, need_bswap);
|
||||||
|
break;
|
||||||
|
case ELFCLASS64:
|
||||||
|
elf64_process(outf, buf, need_bswap);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "%s: invalid elf EI_CLASS (%u)\n",
|
||||||
|
inf_name, buf[EI_CLASS]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(outf, "};\n\n"); /* end vdso_relocs. */
|
||||||
|
|
||||||
|
fprintf(outf, "static const VdsoImageInfo %s_image_info = {\n", prefix);
|
||||||
|
fprintf(outf, " .image = %s_image,\n", prefix);
|
||||||
|
fprintf(outf, " .relocs = %s_relocs,\n", prefix);
|
||||||
|
fprintf(outf, " .image_size = sizeof(%s_image),\n", prefix);
|
||||||
|
fprintf(outf, " .reloc_count = ARRAY_SIZE(%s_relocs),\n", prefix);
|
||||||
|
fprintf(outf, " .sigreturn_ofs = 0x%x,\n", sigreturn_addr);
|
||||||
|
fprintf(outf, " .rt_sigreturn_ofs = 0x%x,\n", rt_sigreturn_addr);
|
||||||
|
fprintf(outf, "};\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Everything should have gone well.
|
||||||
|
*/
|
||||||
|
if (fclose(outf)) {
|
||||||
|
goto perror_outf;
|
||||||
|
}
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
|
perror_inf:
|
||||||
|
perror(inf_name);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
perror_outf:
|
||||||
|
perror(outf_name);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
@ -28,9 +28,13 @@ linux_user_ss.add(when: 'TARGET_HAS_BFLT', if_true: files('flatload.c'))
|
|||||||
linux_user_ss.add(when: 'TARGET_I386', if_true: files('vm86.c'))
|
linux_user_ss.add(when: 'TARGET_I386', if_true: files('vm86.c'))
|
||||||
linux_user_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING', if_true: files('semihost.c'))
|
linux_user_ss.add(when: 'CONFIG_ARM_COMPATIBLE_SEMIHOSTING', if_true: files('semihost.c'))
|
||||||
|
|
||||||
|
|
||||||
syscall_nr_generators = {}
|
syscall_nr_generators = {}
|
||||||
|
|
||||||
|
gen_vdso_exe = executable('gen-vdso', 'gen-vdso.c',
|
||||||
|
native: true, build_by_default: false)
|
||||||
|
gen_vdso = generator(gen_vdso_exe, output: '@BASENAME@.c.inc',
|
||||||
|
arguments: ['-o', '@OUTPUT@', '@EXTRA_ARGS@', '@INPUT@'])
|
||||||
|
|
||||||
subdir('alpha')
|
subdir('alpha')
|
||||||
subdir('arm')
|
subdir('arm')
|
||||||
subdir('hppa')
|
subdir('hppa')
|
||||||
|
Loading…
Reference in New Issue
Block a user