]> git.proxmox.com Git - mirror_qemu.git/blob - linux-user/gen-vdso-elfn.c.inc
iotests: Test two stream jobs in a single iothread
[mirror_qemu.git] / linux-user / gen-vdso-elfn.c.inc
1 /*
2 * Post-process a vdso elf image for inclusion into qemu.
3 * Elf size specialization.
4 *
5 * Copyright 2023 Linaro, Ltd.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 static void elfN(bswap_ehdr)(ElfN(Ehdr) *ehdr)
11 {
12 bswaps(&ehdr->e_type); /* Object file type */
13 bswaps(&ehdr->e_machine); /* Architecture */
14 bswaps(&ehdr->e_version); /* Object file version */
15 bswaps(&ehdr->e_entry); /* Entry point virtual address */
16 bswaps(&ehdr->e_phoff); /* Program header table file offset */
17 bswaps(&ehdr->e_shoff); /* Section header table file offset */
18 bswaps(&ehdr->e_flags); /* Processor-specific flags */
19 bswaps(&ehdr->e_ehsize); /* ELF header size in bytes */
20 bswaps(&ehdr->e_phentsize); /* Program header table entry size */
21 bswaps(&ehdr->e_phnum); /* Program header table entry count */
22 bswaps(&ehdr->e_shentsize); /* Section header table entry size */
23 bswaps(&ehdr->e_shnum); /* Section header table entry count */
24 bswaps(&ehdr->e_shstrndx); /* Section header string table index */
25 }
26
27 static void elfN(bswap_phdr)(ElfN(Phdr) *phdr)
28 {
29 bswaps(&phdr->p_type); /* Segment type */
30 bswaps(&phdr->p_flags); /* Segment flags */
31 bswaps(&phdr->p_offset); /* Segment file offset */
32 bswaps(&phdr->p_vaddr); /* Segment virtual address */
33 bswaps(&phdr->p_paddr); /* Segment physical address */
34 bswaps(&phdr->p_filesz); /* Segment size in file */
35 bswaps(&phdr->p_memsz); /* Segment size in memory */
36 bswaps(&phdr->p_align); /* Segment alignment */
37 }
38
39 static void elfN(bswap_shdr)(ElfN(Shdr) *shdr)
40 {
41 bswaps(&shdr->sh_name);
42 bswaps(&shdr->sh_type);
43 bswaps(&shdr->sh_flags);
44 bswaps(&shdr->sh_addr);
45 bswaps(&shdr->sh_offset);
46 bswaps(&shdr->sh_size);
47 bswaps(&shdr->sh_link);
48 bswaps(&shdr->sh_info);
49 bswaps(&shdr->sh_addralign);
50 bswaps(&shdr->sh_entsize);
51 }
52
53 static void elfN(bswap_sym)(ElfN(Sym) *sym)
54 {
55 bswaps(&sym->st_name);
56 bswaps(&sym->st_value);
57 bswaps(&sym->st_size);
58 bswaps(&sym->st_shndx);
59 }
60
61 static void elfN(bswap_dyn)(ElfN(Dyn) *dyn)
62 {
63 bswaps(&dyn->d_tag); /* Dynamic type tag */
64 bswaps(&dyn->d_un.d_ptr); /* Dynamic ptr or val, in union */
65 }
66
67 static void elfN(search_symtab)(ElfN(Shdr) *shdr, unsigned sym_idx,
68 void *buf, bool need_bswap)
69 {
70 unsigned str_idx = shdr[sym_idx].sh_link;
71 ElfN(Sym) *sym = buf + shdr[sym_idx].sh_offset;
72 unsigned sym_n = shdr[sym_idx].sh_size / sizeof(*sym);
73 const char *str = buf + shdr[str_idx].sh_offset;
74
75 for (unsigned i = 0; i < sym_n; ++i) {
76 const char *name;
77
78 if (need_bswap) {
79 elfN(bswap_sym)(sym + i);
80 }
81 name = str + sym[i].st_name;
82
83 if (sigreturn_sym && strcmp(sigreturn_sym, name) == 0) {
84 sigreturn_addr = sym[i].st_value;
85 }
86 if (rt_sigreturn_sym && strcmp(rt_sigreturn_sym, name) == 0) {
87 rt_sigreturn_addr = sym[i].st_value;
88 }
89 }
90 }
91
92 static void elfN(process)(FILE *outf, void *buf, bool need_bswap)
93 {
94 ElfN(Ehdr) *ehdr = buf;
95 ElfN(Phdr) *phdr;
96 ElfN(Shdr) *shdr;
97 unsigned phnum, shnum;
98 unsigned dynamic_ofs = 0;
99 unsigned dynamic_addr = 0;
100 unsigned symtab_idx = 0;
101 unsigned dynsym_idx = 0;
102 unsigned first_segsz = 0;
103 int errors = 0;
104
105 if (need_bswap) {
106 elfN(bswap_ehdr)(ehdr);
107 }
108
109 phnum = ehdr->e_phnum;
110 phdr = buf + ehdr->e_phoff;
111 if (need_bswap) {
112 for (unsigned i = 0; i < phnum; ++i) {
113 elfN(bswap_phdr)(phdr + i);
114 }
115 }
116
117 shnum = ehdr->e_shnum;
118 shdr = buf + ehdr->e_shoff;
119 if (need_bswap) {
120 for (unsigned i = 0; i < shnum; ++i) {
121 elfN(bswap_shdr)(shdr + i);
122 }
123 }
124 for (unsigned i = 0; i < shnum; ++i) {
125 switch (shdr[i].sh_type) {
126 case SHT_SYMTAB:
127 symtab_idx = i;
128 break;
129 case SHT_DYNSYM:
130 dynsym_idx = i;
131 break;
132 }
133 }
134
135 /*
136 * Validate the VDSO is created as we expect: that PT_PHDR,
137 * PT_DYNAMIC, and PT_NOTE located in a writable data segment.
138 * PHDR and DYNAMIC require relocation, and NOTE will get the
139 * linux version number.
140 */
141 for (unsigned i = 0; i < phnum; ++i) {
142 if (phdr[i].p_type != PT_LOAD) {
143 continue;
144 }
145 if (first_segsz != 0) {
146 fprintf(stderr, "Multiple LOAD segments\n");
147 errors++;
148 }
149 if (phdr[i].p_offset != 0) {
150 fprintf(stderr, "LOAD segment does not cover EHDR\n");
151 errors++;
152 }
153 if (phdr[i].p_vaddr != 0) {
154 fprintf(stderr, "LOAD segment not loaded at address 0\n");
155 errors++;
156 }
157 first_segsz = phdr[i].p_filesz;
158 if (first_segsz < ehdr->e_phoff + phnum * sizeof(*phdr)) {
159 fprintf(stderr, "LOAD segment does not cover PHDRs\n");
160 errors++;
161 }
162 if ((phdr[i].p_flags & (PF_R | PF_W)) != (PF_R | PF_W)) {
163 fprintf(stderr, "LOAD segment is not read-write\n");
164 errors++;
165 }
166 }
167 for (unsigned i = 0; i < phnum; ++i) {
168 const char *which;
169
170 switch (phdr[i].p_type) {
171 case PT_PHDR:
172 which = "PT_PHDR";
173 break;
174 case PT_NOTE:
175 which = "PT_NOTE";
176 break;
177 case PT_DYNAMIC:
178 dynamic_ofs = phdr[i].p_offset;
179 dynamic_addr = phdr[i].p_vaddr;
180 which = "PT_DYNAMIC";
181 break;
182 default:
183 continue;
184 }
185 if (first_segsz < phdr[i].p_vaddr + phdr[i].p_filesz) {
186 fprintf(stderr, "LOAD segment does not cover %s\n", which);
187 errors++;
188 }
189 }
190 if (errors) {
191 exit(EXIT_FAILURE);
192 }
193
194 /* Relocate the program headers. */
195 for (unsigned i = 0; i < phnum; ++i) {
196 output_reloc(outf, buf, &phdr[i].p_vaddr);
197 output_reloc(outf, buf, &phdr[i].p_paddr);
198 }
199
200 /* Relocate the DYNAMIC entries. */
201 if (dynamic_addr) {
202 ElfN(Dyn) *dyn = buf + dynamic_ofs;
203 __typeof(dyn->d_tag) tag;
204
205 do {
206
207 if (need_bswap) {
208 elfN(bswap_dyn)(dyn);
209 }
210 tag = dyn->d_tag;
211
212 switch (tag) {
213 case DT_HASH:
214 case DT_SYMTAB:
215 case DT_STRTAB:
216 case DT_VERDEF:
217 case DT_VERSYM:
218 case DT_PLTGOT:
219 case DT_ADDRRNGLO ... DT_ADDRRNGHI:
220 /* These entries store an address in the entry. */
221 output_reloc(outf, buf, &dyn->d_un.d_val);
222 break;
223
224 case DT_NULL:
225 case DT_STRSZ:
226 case DT_SONAME:
227 case DT_DEBUG:
228 case DT_FLAGS:
229 case DT_FLAGS_1:
230 case DT_SYMBOLIC:
231 case DT_BIND_NOW:
232 case DT_VERDEFNUM:
233 case DT_VALRNGLO ... DT_VALRNGHI:
234 /* These entries store an integer in the entry. */
235 break;
236
237 case DT_SYMENT:
238 if (dyn->d_un.d_val != sizeof(ElfN(Sym))) {
239 fprintf(stderr, "VDSO has incorrect dynamic symbol size\n");
240 errors++;
241 }
242 break;
243
244 case DT_REL:
245 case DT_RELSZ:
246 case DT_RELA:
247 case DT_RELASZ:
248 /*
249 * These entries indicate that the VDSO was built incorrectly.
250 * It should not have any real relocations.
251 * ??? The RISC-V toolchain will emit these even when there
252 * are no relocations. Validate zeros.
253 */
254 if (dyn->d_un.d_val != 0) {
255 fprintf(stderr, "VDSO has dynamic relocations\n");
256 errors++;
257 }
258 break;
259 case DT_RELENT:
260 case DT_RELAENT:
261 case DT_TEXTREL:
262 /* These entries store an integer in the entry. */
263 /* Should not be required; see above. */
264 break;
265
266 case DT_NEEDED:
267 case DT_VERNEED:
268 case DT_PLTREL:
269 case DT_JMPREL:
270 case DT_RPATH:
271 case DT_RUNPATH:
272 fprintf(stderr, "VDSO has external dependencies\n");
273 errors++;
274 break;
275
276 case PT_LOPROC + 3:
277 if (ehdr->e_machine == EM_PPC64) {
278 break; /* DT_PPC64_OPT: integer bitmask */
279 }
280 goto do_default;
281
282 default:
283 do_default:
284 /* This is probably something target specific. */
285 fprintf(stderr, "VDSO has unknown DYNAMIC entry (%lx)\n",
286 (unsigned long)tag);
287 errors++;
288 break;
289 }
290 dyn++;
291 } while (tag != DT_NULL);
292 if (errors) {
293 exit(EXIT_FAILURE);
294 }
295 }
296
297 /* Relocate the dynamic symbol table. */
298 if (dynsym_idx) {
299 ElfN(Sym) *sym = buf + shdr[dynsym_idx].sh_offset;
300 unsigned sym_n = shdr[dynsym_idx].sh_size / sizeof(*sym);
301
302 for (unsigned i = 0; i < sym_n; ++i) {
303 output_reloc(outf, buf, &sym[i].st_value);
304 }
305 }
306
307 /* Search both dynsym and symtab for the signal return symbols. */
308 if (dynsym_idx) {
309 elfN(search_symtab)(shdr, dynsym_idx, buf, need_bswap);
310 }
311 if (symtab_idx) {
312 elfN(search_symtab)(shdr, symtab_idx, buf, need_bswap);
313 }
314 }