qemu

Форк
0
/
gen-vdso-elfn.c.inc 
314 строк · 9.6 Кб
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
}
315

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.