1*2fa536d1SRichard Henderson /*
2*2fa536d1SRichard Henderson * Post-process a vdso elf image for inclusion into qemu.
3*2fa536d1SRichard Henderson *
4*2fa536d1SRichard Henderson * Copyright 2023 Linaro, Ltd.
5*2fa536d1SRichard Henderson *
6*2fa536d1SRichard Henderson * SPDX-License-Identifier: GPL-2.0-or-later
7*2fa536d1SRichard Henderson */
8*2fa536d1SRichard Henderson
9*2fa536d1SRichard Henderson #include <stdlib.h>
10*2fa536d1SRichard Henderson #include <stdbool.h>
11*2fa536d1SRichard Henderson #include <stdint.h>
12*2fa536d1SRichard Henderson #include <stdio.h>
13*2fa536d1SRichard Henderson #include <string.h>
14*2fa536d1SRichard Henderson #include <errno.h>
15*2fa536d1SRichard Henderson #include <endian.h>
16*2fa536d1SRichard Henderson #include <unistd.h>
17*2fa536d1SRichard Henderson #include "elf.h"
18*2fa536d1SRichard Henderson
19*2fa536d1SRichard Henderson
20*2fa536d1SRichard Henderson #define bswap_(p) _Generic(*(p), \
21*2fa536d1SRichard Henderson uint16_t: __builtin_bswap16, \
22*2fa536d1SRichard Henderson uint32_t: __builtin_bswap32, \
23*2fa536d1SRichard Henderson uint64_t: __builtin_bswap64, \
24*2fa536d1SRichard Henderson int16_t: __builtin_bswap16, \
25*2fa536d1SRichard Henderson int32_t: __builtin_bswap32, \
26*2fa536d1SRichard Henderson int64_t: __builtin_bswap64)
27*2fa536d1SRichard Henderson #define bswaps(p) (*(p) = bswap_(p)(*(p)))
28*2fa536d1SRichard Henderson
output_reloc(FILE * outf,void * buf,void * loc)29*2fa536d1SRichard Henderson static void output_reloc(FILE *outf, void *buf, void *loc)
30*2fa536d1SRichard Henderson {
31*2fa536d1SRichard Henderson fprintf(outf, " 0x%08tx,\n", loc - buf);
32*2fa536d1SRichard Henderson }
33*2fa536d1SRichard Henderson
34*2fa536d1SRichard Henderson static const char *sigreturn_sym;
35*2fa536d1SRichard Henderson static const char *rt_sigreturn_sym;
36*2fa536d1SRichard Henderson
37*2fa536d1SRichard Henderson static unsigned sigreturn_addr;
38*2fa536d1SRichard Henderson static unsigned rt_sigreturn_addr;
39*2fa536d1SRichard Henderson
40*2fa536d1SRichard Henderson #define N 32
41*2fa536d1SRichard Henderson #define elfN(x) elf32_##x
42*2fa536d1SRichard Henderson #define ElfN(x) Elf32_##x
43*2fa536d1SRichard Henderson #include "gen-vdso-elfn.c.inc"
44*2fa536d1SRichard Henderson #undef N
45*2fa536d1SRichard Henderson #undef elfN
46*2fa536d1SRichard Henderson #undef ElfN
47*2fa536d1SRichard Henderson
48*2fa536d1SRichard Henderson #define N 64
49*2fa536d1SRichard Henderson #define elfN(x) elf64_##x
50*2fa536d1SRichard Henderson #define ElfN(x) Elf64_##x
51*2fa536d1SRichard Henderson #include "gen-vdso-elfn.c.inc"
52*2fa536d1SRichard Henderson #undef N
53*2fa536d1SRichard Henderson #undef elfN
54*2fa536d1SRichard Henderson #undef ElfN
55*2fa536d1SRichard Henderson
56*2fa536d1SRichard Henderson
main(int argc,char ** argv)57*2fa536d1SRichard Henderson int main(int argc, char **argv)
58*2fa536d1SRichard Henderson {
59*2fa536d1SRichard Henderson FILE *inf, *outf;
60*2fa536d1SRichard Henderson long total_len;
61*2fa536d1SRichard Henderson const char *prefix = "vdso";
62*2fa536d1SRichard Henderson const char *inf_name;
63*2fa536d1SRichard Henderson const char *outf_name = NULL;
64*2fa536d1SRichard Henderson unsigned char *buf;
65*2fa536d1SRichard Henderson bool need_bswap;
66*2fa536d1SRichard Henderson
67*2fa536d1SRichard Henderson while (1) {
68*2fa536d1SRichard Henderson int opt = getopt(argc, argv, "o:p:r:s:");
69*2fa536d1SRichard Henderson if (opt < 0) {
70*2fa536d1SRichard Henderson break;
71*2fa536d1SRichard Henderson }
72*2fa536d1SRichard Henderson switch (opt) {
73*2fa536d1SRichard Henderson case 'o':
74*2fa536d1SRichard Henderson outf_name = optarg;
75*2fa536d1SRichard Henderson break;
76*2fa536d1SRichard Henderson case 'p':
77*2fa536d1SRichard Henderson prefix = optarg;
78*2fa536d1SRichard Henderson break;
79*2fa536d1SRichard Henderson case 'r':
80*2fa536d1SRichard Henderson rt_sigreturn_sym = optarg;
81*2fa536d1SRichard Henderson break;
82*2fa536d1SRichard Henderson case 's':
83*2fa536d1SRichard Henderson sigreturn_sym = optarg;
84*2fa536d1SRichard Henderson break;
85*2fa536d1SRichard Henderson default:
86*2fa536d1SRichard Henderson usage:
87*2fa536d1SRichard Henderson fprintf(stderr, "usage: [-p prefix] [-r rt-sigreturn-name] "
88*2fa536d1SRichard Henderson "[-s sigreturn-name] -o output-file input-file\n");
89*2fa536d1SRichard Henderson return EXIT_FAILURE;
90*2fa536d1SRichard Henderson }
91*2fa536d1SRichard Henderson }
92*2fa536d1SRichard Henderson
93*2fa536d1SRichard Henderson if (optind >= argc || outf_name == NULL) {
94*2fa536d1SRichard Henderson goto usage;
95*2fa536d1SRichard Henderson }
96*2fa536d1SRichard Henderson inf_name = argv[optind];
97*2fa536d1SRichard Henderson
98*2fa536d1SRichard Henderson /*
99*2fa536d1SRichard Henderson * Open the input and output files.
100*2fa536d1SRichard Henderson */
101*2fa536d1SRichard Henderson inf = fopen(inf_name, "rb");
102*2fa536d1SRichard Henderson if (inf == NULL) {
103*2fa536d1SRichard Henderson goto perror_inf;
104*2fa536d1SRichard Henderson }
105*2fa536d1SRichard Henderson outf = fopen(outf_name, "w");
106*2fa536d1SRichard Henderson if (outf == NULL) {
107*2fa536d1SRichard Henderson goto perror_outf;
108*2fa536d1SRichard Henderson }
109*2fa536d1SRichard Henderson
110*2fa536d1SRichard Henderson /*
111*2fa536d1SRichard Henderson * Read the input file into a buffer.
112*2fa536d1SRichard Henderson * We expect the vdso to be small, on the order of one page,
113*2fa536d1SRichard Henderson * therefore we do not expect a partial read.
114*2fa536d1SRichard Henderson */
115*2fa536d1SRichard Henderson fseek(inf, 0, SEEK_END);
116*2fa536d1SRichard Henderson total_len = ftell(inf);
117*2fa536d1SRichard Henderson fseek(inf, 0, SEEK_SET);
118*2fa536d1SRichard Henderson
119*2fa536d1SRichard Henderson buf = malloc(total_len);
120*2fa536d1SRichard Henderson if (buf == NULL) {
121*2fa536d1SRichard Henderson goto perror_inf;
122*2fa536d1SRichard Henderson }
123*2fa536d1SRichard Henderson
124*2fa536d1SRichard Henderson errno = 0;
125*2fa536d1SRichard Henderson if (fread(buf, 1, total_len, inf) != total_len) {
126*2fa536d1SRichard Henderson if (errno) {
127*2fa536d1SRichard Henderson goto perror_inf;
128*2fa536d1SRichard Henderson }
129*2fa536d1SRichard Henderson fprintf(stderr, "%s: incomplete read\n", inf_name);
130*2fa536d1SRichard Henderson return EXIT_FAILURE;
131*2fa536d1SRichard Henderson }
132*2fa536d1SRichard Henderson fclose(inf);
133*2fa536d1SRichard Henderson
134*2fa536d1SRichard Henderson /*
135*2fa536d1SRichard Henderson * Write out the vdso image now, before we make local changes.
136*2fa536d1SRichard Henderson */
137*2fa536d1SRichard Henderson
138*2fa536d1SRichard Henderson fprintf(outf,
139*2fa536d1SRichard Henderson "/* Automatically generated from linux-user/gen-vdso.c. */\n"
140*2fa536d1SRichard Henderson "\n"
141*2fa536d1SRichard Henderson "static const uint8_t %s_image[] = {",
142*2fa536d1SRichard Henderson prefix);
143*2fa536d1SRichard Henderson for (long i = 0; i < total_len; ++i) {
144*2fa536d1SRichard Henderson if (i % 12 == 0) {
145*2fa536d1SRichard Henderson fputs("\n ", outf);
146*2fa536d1SRichard Henderson }
147*2fa536d1SRichard Henderson fprintf(outf, " 0x%02x,", buf[i]);
148*2fa536d1SRichard Henderson }
149*2fa536d1SRichard Henderson fprintf(outf, "\n};\n\n");
150*2fa536d1SRichard Henderson
151*2fa536d1SRichard Henderson /*
152*2fa536d1SRichard Henderson * Identify which elf flavor we're processing.
153*2fa536d1SRichard Henderson * The first 16 bytes of the file are e_ident.
154*2fa536d1SRichard Henderson */
155*2fa536d1SRichard Henderson
156*2fa536d1SRichard Henderson if (buf[EI_MAG0] != ELFMAG0 || buf[EI_MAG1] != ELFMAG1 ||
157*2fa536d1SRichard Henderson buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) {
158*2fa536d1SRichard Henderson fprintf(stderr, "%s: not an elf file\n", inf_name);
159*2fa536d1SRichard Henderson return EXIT_FAILURE;
160*2fa536d1SRichard Henderson }
161*2fa536d1SRichard Henderson switch (buf[EI_DATA]) {
162*2fa536d1SRichard Henderson case ELFDATA2LSB:
163*2fa536d1SRichard Henderson need_bswap = BYTE_ORDER != LITTLE_ENDIAN;
164*2fa536d1SRichard Henderson break;
165*2fa536d1SRichard Henderson case ELFDATA2MSB:
166*2fa536d1SRichard Henderson need_bswap = BYTE_ORDER != BIG_ENDIAN;
167*2fa536d1SRichard Henderson break;
168*2fa536d1SRichard Henderson default:
169*2fa536d1SRichard Henderson fprintf(stderr, "%s: invalid elf EI_DATA (%u)\n",
170*2fa536d1SRichard Henderson inf_name, buf[EI_DATA]);
171*2fa536d1SRichard Henderson return EXIT_FAILURE;
172*2fa536d1SRichard Henderson }
173*2fa536d1SRichard Henderson
174*2fa536d1SRichard Henderson /*
175*2fa536d1SRichard Henderson * We need to relocate the VDSO image. The one built into the kernel
176*2fa536d1SRichard Henderson * is built for a fixed address. The one we built for QEMU is not,
177*2fa536d1SRichard Henderson * since that requires close control of the guest address space.
178*2fa536d1SRichard Henderson *
179*2fa536d1SRichard Henderson * Output relocation addresses as we go.
180*2fa536d1SRichard Henderson */
181*2fa536d1SRichard Henderson
182*2fa536d1SRichard Henderson fprintf(outf, "static const unsigned %s_relocs[] = {\n", prefix);
183*2fa536d1SRichard Henderson
184*2fa536d1SRichard Henderson switch (buf[EI_CLASS]) {
185*2fa536d1SRichard Henderson case ELFCLASS32:
186*2fa536d1SRichard Henderson elf32_process(outf, buf, need_bswap);
187*2fa536d1SRichard Henderson break;
188*2fa536d1SRichard Henderson case ELFCLASS64:
189*2fa536d1SRichard Henderson elf64_process(outf, buf, need_bswap);
190*2fa536d1SRichard Henderson break;
191*2fa536d1SRichard Henderson default:
192*2fa536d1SRichard Henderson fprintf(stderr, "%s: invalid elf EI_CLASS (%u)\n",
193*2fa536d1SRichard Henderson inf_name, buf[EI_CLASS]);
194*2fa536d1SRichard Henderson return EXIT_FAILURE;
195*2fa536d1SRichard Henderson }
196*2fa536d1SRichard Henderson
197*2fa536d1SRichard Henderson fprintf(outf, "};\n\n"); /* end vdso_relocs. */
198*2fa536d1SRichard Henderson
199*2fa536d1SRichard Henderson fprintf(outf, "static const VdsoImageInfo %s_image_info = {\n", prefix);
200*2fa536d1SRichard Henderson fprintf(outf, " .image = %s_image,\n", prefix);
201*2fa536d1SRichard Henderson fprintf(outf, " .relocs = %s_relocs,\n", prefix);
202*2fa536d1SRichard Henderson fprintf(outf, " .image_size = sizeof(%s_image),\n", prefix);
203*2fa536d1SRichard Henderson fprintf(outf, " .reloc_count = ARRAY_SIZE(%s_relocs),\n", prefix);
204*2fa536d1SRichard Henderson fprintf(outf, " .sigreturn_ofs = 0x%x,\n", sigreturn_addr);
205*2fa536d1SRichard Henderson fprintf(outf, " .rt_sigreturn_ofs = 0x%x,\n", rt_sigreturn_addr);
206*2fa536d1SRichard Henderson fprintf(outf, "};\n");
207*2fa536d1SRichard Henderson
208*2fa536d1SRichard Henderson /*
209*2fa536d1SRichard Henderson * Everything should have gone well.
210*2fa536d1SRichard Henderson */
211*2fa536d1SRichard Henderson if (fclose(outf)) {
212*2fa536d1SRichard Henderson goto perror_outf;
213*2fa536d1SRichard Henderson }
214*2fa536d1SRichard Henderson return EXIT_SUCCESS;
215*2fa536d1SRichard Henderson
216*2fa536d1SRichard Henderson perror_inf:
217*2fa536d1SRichard Henderson perror(inf_name);
218*2fa536d1SRichard Henderson return EXIT_FAILURE;
219*2fa536d1SRichard Henderson
220*2fa536d1SRichard Henderson perror_outf:
221*2fa536d1SRichard Henderson perror(outf_name);
222*2fa536d1SRichard Henderson return EXIT_FAILURE;
223*2fa536d1SRichard Henderson }
224