xref: /qemu/linux-user/gen-vdso.c (revision 2fa536d1)
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