:: limine / common / lib / elf.c 38.4 KB raw

1
#include <stdint.h>
2
#include <stddef.h>
3
#include <lib/misc.h>
4
#include <sys/cpu.h>
5
#include <lib/libc.h>
6
#include <lib/elf.h>
7
#include <lib/print.h>
8
#include <lib/rand.h>
9
#include <lib/elsewhere.h>
10
#include <mm/pmm.h>
11
#include <fs/file.h>
12
13
#define ET_NONE     0
14
#define ET_REL      1
15
#define ET_EXEC     2
16
#define ET_DYN      3
17
18
#define PT_LOAD     0x00000001
19
#define PT_DYNAMIC  0x00000002
20
#define PT_INTERP   0x00000003
21
#define PT_PHDR     0x00000006
22
23
#define DT_NULL     0x00000000
24
#define DT_NEEDED   0x00000001
25
#define DT_RELA     0x00000007
26
#define DT_RELASZ   0x00000008
27
#define DT_RELAENT  0x00000009
28
#define DT_RELR     0x00000024
29
#define DT_RELRSZ   0x00000023
30
#define DT_RELRENT  0x00000025
31
#define DT_SYMTAB   0x00000006
32
#define DT_SYMENT   0x0000000b
33
#define DT_STRTAB   0x00000005
34
#define DT_PLTREL   0x00000014
35
#define DT_PLTRELSZ 0x00000002
36
#define DT_JMPREL   0x00000017
37
#define DT_FLAGS_1  0x6ffffffb
38
39
#define DF_1_PIE    0x08000000
40
41
#define ABI_SYSV     0x00
42
#define ARCH_X86_64  0x3e
43
#define ARCH_X86_32  0x03
44
#define ARCH_AARCH64 0xb7
45
#define ARCH_RISCV   0xf3
46
#define ARCH_LOONGARCH 0x102
47
#define BITS_LE      0x01
48
#define ELFCLASS32   0x01
49
#define ELFCLASS64   0x02
50
#define SHT_RELA     0x00000004
51
#define SHN_UNDEF    0x00000000
52
#define STB_WEAK     0x00000002
53
#define R_X86_64_NONE      0x00000000
54
#define R_AARCH64_NONE     0x00000000
55
#define R_RISCV_NONE       0x00000000
56
#define R_LARCH_NONE       0x00000000
57
#define R_X86_64_RELATIVE  0x00000008
58
#define R_AARCH64_RELATIVE 0x00000403
59
#define R_RISCV_RELATIVE   0x00000003
60
#define R_LARCH_RELATIVE   0x00000003
61
#define R_X86_64_GLOB_DAT  0x00000006
62
#define R_AARCH64_GLOB_DAT 0x00000401
63
#define R_X86_64_JUMP_SLOT 0x00000007
64
#define R_AARCH64_JUMP_SLOT 0x00000402
65
#define R_RISCV_JUMP_SLOT  0x00000005
66
#define R_LARCH_JUMP_SLOT  0x00000005
67
#define R_X86_64_64        0x00000001
68
#define R_RISCV_64         0x00000002
69
#define R_LARCH_64         0x00000002
70
#define R_AARCH64_ABS64    0x00000101
71
72
#define R_INTERNAL_RELR    0xfffffff0
73
74
/* Indices into identification array */
75
#define EI_CLASS    4
76
#define EI_DATA     5
77
#define EI_VERSION  6
78
#define EI_OSABI    7
79
80
struct elf32_hdr {
81
    uint8_t  ident[16];
82
    uint16_t type;
83
    uint16_t machine;
84
    uint32_t version;
85
    uint32_t entry;
86
    uint32_t phoff;
87
    uint32_t shoff;
88
    uint32_t flags;
89
    uint16_t hdr_size;
90
    uint16_t phdr_size;
91
    uint16_t ph_num;
92
    uint16_t shdr_size;
93
    uint16_t sh_num;
94
    uint16_t shstrndx;
95
};
96
97
struct elf64_phdr {
98
    uint32_t p_type;
99
    uint32_t p_flags;
100
    uint64_t p_offset;
101
    uint64_t p_vaddr;
102
    uint64_t p_paddr;
103
    uint64_t p_filesz;
104
    uint64_t p_memsz;
105
    uint64_t p_align;
106
};
107
108
struct elf32_phdr {
109
    uint32_t p_type;
110
    uint32_t p_offset;
111
    uint32_t p_vaddr;
112
    uint32_t p_paddr;
113
    uint32_t p_filesz;
114
    uint32_t p_memsz;
115
    uint32_t p_flags;
116
    uint32_t p_align;
117
};
118
119
struct elf64_rela {
120
    uint64_t r_addr;
121
    uint32_t r_info;
122
    uint32_t r_symbol;
123
    uint64_t r_addend;
124
};
125
126
struct elf32_dyn {
127
    uint32_t d_tag;
128
    uint32_t d_un;
129
};
130
131
struct elf64_dyn {
132
    uint64_t d_tag;
133
    uint64_t d_un;
134
};
135
136
static bool elf32_validate(struct elf32_hdr *hdr) {
137
    if (strncmp((char *)hdr->ident, "\177ELF", 4)) {
138
        panic(true, "elf: Not a valid ELF file.");
139
    }
140
141
    if (hdr->ident[EI_DATA] != BITS_LE) {
142
        panic(true, "elf: Not a Little-endian ELF file.");
143
    }
144
145
    if (hdr->machine != ARCH_X86_32) {
146
        panic(true, "elf: Not an IA-32 ELF file.");
147
    }
148
149
    return true;
150
}
151
152
static bool elf64_validate(struct elf64_hdr *hdr) {
153
    if (strncmp((char *)hdr->ident, "\177ELF", 4)) {
154
        panic(true, "elf: Not a valid ELF file.");
155
    }
156
157
    if (hdr->ident[EI_DATA] != BITS_LE) {
158
        panic(true, "elf: Not a Little-endian ELF file.");
159
    }
160
161
#if defined (__x86_64__) || defined (__i386__)
162
    if (hdr->machine != ARCH_X86_64) {
163
        panic(true, "elf: Not an x86-64 ELF file.");
164
    }
165
#elif defined (__aarch64__)
166
    if (hdr->machine != ARCH_AARCH64) {
167
        panic(true, "elf: Not an aarch64 ELF file.");
168
    }
169
#elif defined (__riscv)
170
    if (hdr->machine != ARCH_RISCV && hdr->ident[EI_CLASS] == ELFCLASS64) {
171
        panic(true, "elf: Not a riscv64 ELF file.");
172
    }
173
#elif defined (__loongarch64)
174
    if (hdr->machine != ARCH_LOONGARCH && hdr->ident[EI_CLASS] == ELFCLASS64) {
175
        panic(true, "elf: Not a loongarch64 ELF file.");
176
    }
177
#else
178
#error Unknown architecture
179
#endif
180
181
    return true;
182
}
183
184
int elf_bits(uint8_t *elf, size_t file_size) {
185
    if (file_size < sizeof(struct elf64_hdr)) {
186
        return -1;
187
    }
188
189
    struct elf64_hdr *hdr = (void *)elf;
190
191
    if (strncmp((char *)hdr->ident, "\177ELF", 4)) {
192
        return -1;
193
    }
194
195
    switch (hdr->machine) {
196
        case ARCH_X86_64:
197
        case ARCH_AARCH64:
198
            return 64;
199
        case ARCH_RISCV:
200
        case ARCH_LOONGARCH:
201
            if (hdr->ident[EI_CLASS] == ELFCLASS64) return 64;
202
            if (hdr->ident[EI_CLASS] == ELFCLASS32) return 32;
203
            return -1;
204
        case ARCH_X86_32:
205
            return 32;
206
        default:
207
            return -1;
208
    }
209
}
210
211
struct elf_section_hdr_info elf64_section_hdr_info(uint8_t *elf, size_t file_size) {
212
    struct elf_section_hdr_info info = {0};
213
214
    struct elf64_hdr *hdr = (void *)elf;
215
216
    elf64_validate(hdr);
217
218
    if (CHECKED_ADD((uint64_t)hdr->sh_num * hdr->shdr_size,
219
            hdr->shoff, return info) > file_size) {
220
        return info;
221
    }
222
223
    info.num = hdr->sh_num;
224
    info.section_entry_size = hdr->shdr_size;
225
    info.str_section_idx = hdr->shstrndx;
226
    info.section_offset = hdr->shoff;
227
228
    return info;
229
}
230
231
struct elf_section_hdr_info elf32_section_hdr_info(uint8_t *elf, size_t file_size) {
232
    struct elf_section_hdr_info info = {0};
233
234
    struct elf32_hdr *hdr = (void *)elf;
235
236
    elf32_validate(hdr);
237
238
    if (CHECKED_ADD((uint64_t)hdr->sh_num * hdr->shdr_size,
239
            hdr->shoff, return info) > file_size) {
240
        return info;
241
    }
242
243
    info.num = hdr->sh_num;
244
    info.section_entry_size = hdr->shdr_size;
245
    info.str_section_idx = hdr->shstrndx;
246
    info.section_offset = hdr->shoff;
247
248
    return info;
249
}
250
251
static bool elf64_is_relocatable(uint8_t *elf, struct elf64_hdr *hdr) {
252
    if (hdr->phdr_size < sizeof(struct elf64_phdr)) {
253
        panic(true, "elf: phdr_size < sizeof(struct elf64_phdr)");
254
    }
255
256
    if (hdr->type != ET_DYN) {
257
        return false;
258
    }
259
260
    // Find PT_DYNAMIC segment
261
    for (size_t i = 0; i < hdr->ph_num; i++) {
262
        struct elf64_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
263
264
        if (phdr->p_type != PT_DYNAMIC) {
265
            continue;
266
        }
267
268
        if (phdr->p_filesz == 0) {
269
            panic(true, "elf: ELF file type is ET_DYN, but PT_DYNAMIC segment has 0 size");
270
        }
271
272
        return true;
273
    }
274
275
    panic(true, "elf: ELF file type is ET_DYN, but PT_DYNAMIC segment missing");
276
}
277
278
// Translate a virtual address to a file offset using the phdr table.
279
// Returns false if the vaddr is not found in any PT_LOAD segment or the
280
// translated offset exceeds file bounds.
281
static bool elf64_translate_vaddr(uint8_t *elf, size_t file_size,
282
        struct elf64_hdr *hdr, uint64_t *offset, uint64_t size_hint,
283
        uint64_t *out_seg_size) {
284
    for (uint16_t i = 0; i < hdr->ph_num; i++) {
285
        struct elf64_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
286
287
        uint64_t seg_end = CHECKED_ADD(phdr->p_vaddr, phdr->p_filesz, continue);
288
289
        if (phdr->p_vaddr <= *offset && seg_end > *offset) {
290
            if (out_seg_size != NULL) {
291
                *out_seg_size = phdr->p_filesz - (*offset - phdr->p_vaddr);
292
            }
293
            *offset -= phdr->p_vaddr;
294
            *offset += phdr->p_offset;
295
296
            // Validate translated offset + size_hint is within file
297
            if (CHECKED_ADD(*offset, size_hint, return false) > file_size) {
298
                return false;
299
            }
300
            return true;
301
        }
302
    }
303
    return false;
304
}
305
306
static void elf64_add_relocation_count(size_t *count, uint64_t add) {
307
    if (add > SIZE_MAX - *count) {
308
        panic(true, "elf: relocation count overflow");
309
    }
310
311
    *count += (size_t)add;
312
}
313
314
static bool elf64_apply_relocations(uint8_t *elf, size_t file_size, struct elf64_hdr *hdr, void *buffer, uint64_t vaddr, size_t size, uint64_t slide) {
315
    if (hdr->phdr_size < sizeof(struct elf64_phdr)) {
316
        panic(true, "elf: phdr_size < sizeof(struct elf64_phdr)");
317
    }
318
319
    uint64_t symtab_offset = 0;
320
    uint64_t symtab_ent = 0;
321
    uint64_t symtab_size = 0;  // Size of symbol table (if known)
322
    uint64_t strtab_offset = 0;
323
    uint64_t strtab_size = 0;  // Size of string table (if known)
324
325
    uint64_t dt_pltrel = 0;
326
    uint64_t dt_pltrelsz = 0;
327
    uint64_t dt_jmprel = 0;
328
329
    uint64_t relr_offset = 0;
330
    uint64_t relr_size = 0;
331
    uint64_t relr_ent = 0;
332
333
    uint64_t rela_offset = 0;
334
    uint64_t rela_size = 0;
335
    uint64_t rela_ent = 0;
336
337
    // Validate phdr table is within file bounds
338
    if (CHECKED_ADD(hdr->phoff, CHECKED_MUL((uint64_t)hdr->ph_num, (uint64_t)hdr->phdr_size,
339
            return false), return false) > file_size) {
340
        return false;
341
    }
342
343
    // Find DYN segment
344
    for (uint16_t i = 0; i < hdr->ph_num; i++) {
345
        struct elf64_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
346
347
        if (phdr->p_type != PT_DYNAMIC)
348
            continue;
349
350
        // Validate PT_DYNAMIC segment is within file bounds
351
        if (CHECKED_ADD(phdr->p_offset, phdr->p_filesz, return false) > file_size) {
352
            return false;
353
        }
354
355
        for (uint64_t j = 0; j < phdr->p_filesz / sizeof(struct elf64_dyn); j++) {
356
            struct elf64_dyn *dyn = (void *)elf + (phdr->p_offset + j * sizeof(struct elf64_dyn));
357
358
            switch (dyn->d_tag) {
359
                case DT_RELA:
360
                    rela_offset = dyn->d_un;
361
                    break;
362
                case DT_RELAENT:
363
                    rela_ent = dyn->d_un;
364
                    break;
365
                case DT_RELASZ:
366
                    rela_size = dyn->d_un;
367
                    break;
368
                case DT_RELR:
369
                    relr_offset = dyn->d_un;
370
                    break;
371
                case DT_RELRENT:
372
                    relr_ent = dyn->d_un;
373
                    break;
374
                case DT_RELRSZ:
375
                    relr_size = dyn->d_un;
376
                    break;
377
                case DT_SYMTAB:
378
                    symtab_offset = dyn->d_un;
379
                    break;
380
                case DT_STRTAB:
381
                    strtab_offset = dyn->d_un;
382
                    break;
383
                case DT_SYMENT:
384
                    symtab_ent = dyn->d_un;
385
                    if (symtab_ent < sizeof(struct elf64_sym)) {
386
                        panic(true, "elf: symtab_ent < sizeof(struct elf64_sym)");
387
                    }
388
                    break;
389
                case DT_PLTREL:
390
                    dt_pltrel = dyn->d_un;
391
                    break;
392
                case DT_PLTRELSZ:
393
                    dt_pltrelsz = dyn->d_un;
394
                    break;
395
                case DT_JMPREL:
396
                    dt_jmprel = dyn->d_un;
397
                    break;
398
                case DT_NEEDED:
399
                    panic(true, "elf: ELF file attempts to load a dynamically linked library");
400
                case DT_NULL:
401
                    goto end_of_pt_segment;
402
            }
403
        }
404
405
        break;
406
    }
407
end_of_pt_segment:
408
409
    if (rela_offset != 0) {
410
        if (!elf64_translate_vaddr(elf, file_size, hdr, &rela_offset, rela_size, NULL)) {
411
            panic(true, "elf: RELA vaddr translation failed or out of bounds");
412
        }
413
    }
414
415
    if (relr_offset != 0) {
416
        if (!elf64_translate_vaddr(elf, file_size, hdr, &relr_offset, relr_size, NULL)) {
417
            panic(true, "elf: RELR vaddr translation failed or out of bounds");
418
        }
419
    }
420
421
    if (symtab_offset != 0) {
422
        if (!elf64_translate_vaddr(elf, file_size, hdr, &symtab_offset, 0, &symtab_size)) {
423
            panic(true, "elf: SYMTAB vaddr translation failed or out of bounds");
424
        }
425
    }
426
427
    if (strtab_offset != 0) {
428
        if (!elf64_translate_vaddr(elf, file_size, hdr, &strtab_offset, 0, &strtab_size)) {
429
            panic(true, "elf: STRTAB vaddr translation failed or out of bounds");
430
        }
431
    }
432
433
    if (dt_jmprel != 0) {
434
        if (!elf64_translate_vaddr(elf, file_size, hdr, &dt_jmprel, dt_pltrelsz, NULL)) {
435
            panic(true, "elf: JMPREL vaddr translation failed or out of bounds");
436
        }
437
    }
438
439
    size_t relocs_i = 0;
440
    if (relr_size != 0) {
441
        if (relr_ent != 8) {
442
            panic(true, "elf: relr_ent != 8");
443
        }
444
        for (size_t i = 0; i < relr_size / relr_ent; i++) {
445
            uint64_t entry = *((uint64_t *)(elf + relr_offset + i * relr_ent));
446
447
            if ((entry & 1) == 0) {
448
                elf64_add_relocation_count(&relocs_i, 1);
449
            } else {
450
                elf64_add_relocation_count(&relocs_i, __builtin_popcountll(entry) - 1);
451
            }
452
        }
453
    }
454
    size_t relr_count = relocs_i;
455
    if (rela_size != 0) {
456
        if (rela_ent < sizeof(struct elf64_rela)) {
457
            panic(true, "elf: rela_ent < sizeof(struct elf64_rela)");
458
        }
459
        if (rela_size % rela_ent != 0) {
460
            panic(true, "elf: rela_size not a multiple of rela_ent");
461
        }
462
        elf64_add_relocation_count(&relocs_i, rela_size / rela_ent);
463
    }
464
    if (dt_pltrelsz != 0) {
465
        if (dt_pltrel != DT_RELA) {
466
            panic(true, "elf: dt_pltrel != DT_RELA");
467
        }
468
        if (rela_ent == 0) {
469
            panic(true, "elf: dt_pltrelsz != 0 but rela_ent == 0");
470
        }
471
        if (dt_pltrelsz % rela_ent != 0) {
472
            panic(true, "elf: dt_pltrelsz not a multiple of rela_ent");
473
        }
474
        elf64_add_relocation_count(&relocs_i, dt_pltrelsz / rela_ent);
475
    }
476
    struct elf64_rela **relocs = ext_mem_alloc_counted(relocs_i, sizeof(struct elf64_rela *));
477
478
    if (relr_size != 0) {
479
        size_t relr_i;
480
        for (relr_i = 0; relr_i < relr_count; relr_i++) {
481
            relocs[relr_i] = ext_mem_alloc(sizeof(struct elf64_rela));
482
            relocs[relr_i]->r_info = R_INTERNAL_RELR;
483
        }
484
485
        // This logic is partially lifted from https://maskray.me/blog/2021-10-31-relative-relocations-and-relr
486
        uint64_t where = 0;
487
        relr_i = 0;
488
        for (size_t i = 0; i < relr_size / relr_ent; i++) {
489
            uint64_t entry = *((uint64_t *)(elf + relr_offset + i * relr_ent));
490
491
            if ((entry & 1) == 0) {
492
                where = entry;
493
                relocs[relr_i++]->r_addr = where;
494
                where += 8;
495
            } else {
496
                for (size_t j = 0; (entry >>= 1) != 0; j++) {
497
                    if ((entry & 1) != 0) {
498
                        relocs[relr_i++]->r_addr = where + j * 8;
499
                    }
500
                }
501
                where += 63 * 8;
502
            }
503
        }
504
    }
505
506
    if (rela_size != 0) {
507
        for (uint64_t i = relr_count, offset = 0; offset < rela_size; offset += rela_ent) {
508
            relocs[i++] = (void *)elf + (rela_offset + offset);
509
        }
510
    }
511
512
    if (dt_pltrelsz != 0) {
513
        for (uint64_t i = relr_count + rela_size / rela_ent, offset = 0; offset < dt_pltrelsz; offset += rela_ent) {
514
            relocs[i++] = (void *)elf + (dt_jmprel + offset);
515
        }
516
    }
517
518
    for (size_t i = 0; i < relocs_i; i++) {
519
        struct elf64_rela *relocation = relocs[i];
520
521
        // Relocation is before buffer
522
        if (relocation->r_addr < vaddr)
523
            continue;
524
525
        // Relocation is after buffer
526
        if (size < 8 || relocation->r_addr > vaddr + size - 8)
527
            continue;
528
529
        // It's inside it, calculate where it is
530
        uint64_t *ptr = (uint64_t *)(buffer + (relocation->r_addr - vaddr));
531
532
        switch (relocation->r_info) {
533
#if defined (__x86_64__) || defined (__i386__)
534
            case R_X86_64_NONE:
535
#elif defined (__aarch64__)
536
            case R_AARCH64_NONE:
537
#elif defined (__riscv)
538
            case R_RISCV_NONE:
539
#elif defined (__loongarch64)
540
            case R_LARCH_NONE:
541
#endif
542
            {
543
                break;
544
            }
545
#if defined (__x86_64__) || defined (__i386__)
546
            case R_X86_64_RELATIVE:
547
#elif defined (__aarch64__)
548
            case R_AARCH64_RELATIVE:
549
#elif defined (__riscv)
550
            case R_RISCV_RELATIVE:
551
#elif defined (__loongarch64)
552
            case R_LARCH_RELATIVE:
553
#endif
554
            {
555
                *ptr = slide + relocation->r_addend;
556
                break;
557
            }
558
            case R_INTERNAL_RELR:
559
            {
560
                *ptr += slide;
561
                break;
562
            }
563
#if defined (__x86_64__) || defined (__i386__)
564
            case R_X86_64_GLOB_DAT:
565
            case R_X86_64_JUMP_SLOT:
566
#elif defined (__aarch64__)
567
            case R_AARCH64_GLOB_DAT:
568
            case R_AARCH64_JUMP_SLOT:
569
#elif defined (__riscv)
570
            case R_RISCV_JUMP_SLOT:
571
#elif defined (__loongarch64)
572
            case R_LARCH_JUMP_SLOT:
573
#endif
574
            {
575
                if (symtab_offset == 0 || symtab_ent == 0) {
576
                    panic(true, "elf: Relocation requires symbol table but none present");
577
                }
578
                if (symtab_size == 0) {
579
                    panic(true, "elf: Symtab vaddr translation failed");
580
                }
581
                // Validate symbol index is within bounds
582
                uint64_t sym_offset = CHECKED_MUL(symtab_ent, (uint64_t)relocation->r_symbol,
583
                    panic(true, "elf: Symbol offset overflow"));
584
                if (symtab_size < sizeof(struct elf64_sym)
585
                 || sym_offset > symtab_size - sizeof(struct elf64_sym)) {
586
                    panic(true, "elf: Symbol index %u out of bounds", relocation->r_symbol);
587
                }
588
                struct elf64_sym *s = (void *)elf + symtab_offset + sym_offset;
589
                if (s->st_shndx == SHN_UNDEF) {
590
                    if ((s->st_info >> 4) == STB_WEAK) {
591
                        *ptr = 0;
592
                        break;
593
                    }
594
                    if (strtab_size == 0) {
595
                        panic(true, "elf: Strtab vaddr translation failed");
596
                    }
597
                    // Validate string table access
598
                    if (s->st_name >= strtab_size) {
599
                        panic(true, "elf: Symbol name offset out of bounds");
600
                    }
601
                    panic(true, "elf: Unresolved symbol \"%s\"", elf + strtab_offset + s->st_name);
602
                }
603
                *ptr = slide + s->st_value
604
#if defined (__aarch64__)
605
                       + relocation->r_addend
606
#endif
607
                ;
608
                break;
609
            }
610
#if defined (__x86_64__) || defined (__i386__)
611
            case R_X86_64_64:
612
#elif defined (__aarch64__)
613
            case R_AARCH64_ABS64:
614
#elif defined (__riscv)
615
            case R_RISCV_64:
616
#elif defined (__loongarch64)
617
            case R_LARCH_64:
618
#endif
619
            {
620
                if (symtab_offset == 0 || symtab_ent == 0) {
621
                    panic(true, "elf: Relocation requires symbol table but none present");
622
                }
623
                if (symtab_size == 0) {
624
                    panic(true, "elf: Symtab vaddr translation failed");
625
                }
626
                // Validate symbol index is within bounds
627
                uint64_t sym_offset = CHECKED_MUL(symtab_ent, (uint64_t)relocation->r_symbol,
628
                    panic(true, "elf: Symbol offset overflow"));
629
                if (symtab_size < sizeof(struct elf64_sym)
630
                 || sym_offset > symtab_size - sizeof(struct elf64_sym)) {
631
                    panic(true, "elf: Symbol index %u out of bounds", relocation->r_symbol);
632
                }
633
                struct elf64_sym *s = (void *)elf + symtab_offset + sym_offset;
634
                if (s->st_shndx == SHN_UNDEF) {
635
                    if ((s->st_info >> 4) == STB_WEAK) {
636
                        *ptr = 0;
637
                        break;
638
                    }
639
                    if (strtab_size == 0) {
640
                        panic(true, "elf: Strtab vaddr translation failed");
641
                    }
642
                    // Validate string table access
643
                    if (s->st_name >= strtab_size) {
644
                        panic(true, "elf: Symbol name offset out of bounds");
645
                    }
646
                    panic(true, "elf: Unresolved symbol \"%s\"", elf + strtab_offset + s->st_name);
647
                }
648
                *ptr = slide + s->st_value + relocation->r_addend;
649
                break;
650
            }
651
            default: {
652
                panic(true, "elf: Unknown relocation type: %x", relocation->r_info);
653
            }
654
        }
655
    }
656
657
    for (size_t i = 0; i < relr_count; i++) {
658
        pmm_free(relocs[i], sizeof(struct elf64_rela));
659
    }
660
    pmm_free(relocs, relocs_i * sizeof(struct elf64_rela *));
661
662
    return true;
663
}
664
665
bool elf64_load_section(uint8_t *elf, size_t file_size, void *buffer, const char *name, size_t limit, uint64_t slide) {
666
    struct elf64_hdr *hdr = (void *)elf;
667
668
    elf64_validate(hdr);
669
670
    if (hdr->sh_num == 0) {
671
        return false;
672
    }
673
674
    if (hdr->shdr_size < sizeof(struct elf64_shdr)) {
675
        panic(true, "elf: shdr_size < sizeof(struct elf64_shdr)");
676
    }
677
678
    if (hdr->shstrndx >= hdr->sh_num) {
679
        return false;
680
    }
681
682
    // Validate section header table is within file bounds
683
    uint64_t shdr_table_end = CHECKED_ADD(hdr->shoff,
684
        CHECKED_MUL((uint64_t)hdr->sh_num, (uint64_t)hdr->shdr_size, return false),
685
        return false);
686
    if (shdr_table_end > file_size) {
687
        return false;
688
    }
689
690
    struct elf64_shdr *shstrtab = (void *)elf + (hdr->shoff + hdr->shstrndx * hdr->shdr_size);
691
692
    // Validate shstrtab offset and size are within file bounds
693
    if (shstrtab->sh_offset >= file_size || shstrtab->sh_size > file_size - shstrtab->sh_offset) {
694
        return false;
695
    }
696
697
    char *names = (void *)elf + shstrtab->sh_offset;
698
699
    for (uint16_t i = 0; i < hdr->sh_num; i++) {
700
        struct elf64_shdr *section = (void *)elf + (hdr->shoff + i * hdr->shdr_size);
701
702
        // Validate sh_name is within the string table
703
        if (section->sh_name >= shstrtab->sh_size) {
704
            continue;
705
        }
706
707
        // Ensure the string is NUL-terminated within the string table
708
        if (!memchr(&names[section->sh_name], '\0', shstrtab->sh_size - section->sh_name)) {
709
            continue;
710
        }
711
712
        if (strcmp(&names[section->sh_name], name) == 0) {
713
            // Validate section data is within file bounds
714
            if (section->sh_offset >= file_size || section->sh_size > file_size - section->sh_offset) {
715
                return false;
716
            }
717
718
            if (limit == 0) {
719
                *(void **)buffer = ext_mem_alloc(section->sh_size);
720
                buffer = *(void **)buffer;
721
                limit = section->sh_size;
722
            }
723
            if (section->sh_size > limit) {
724
                return false;
725
            }
726
            memcpy(buffer, elf + section->sh_offset, section->sh_size);
727
            return elf64_apply_relocations(elf, file_size, hdr, buffer, section->sh_addr, section->sh_size, slide);
728
        }
729
    }
730
731
    return false;
732
}
733
734
static uint64_t elf64_max_align(uint8_t *elf) {
735
    uint64_t ret = 0;
736
737
    struct elf64_hdr *hdr = (void *)elf;
738
739
    if (hdr->phdr_size < sizeof(struct elf64_phdr)) {
740
        panic(true, "elf: phdr_size < sizeof(struct elf64_phdr)");
741
    }
742
743
    for (uint16_t i = 0; i < hdr->ph_num; i++) {
744
        struct elf64_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
745
746
        if (phdr->p_type != PT_LOAD || phdr->p_memsz == 0) {
747
            continue;
748
        }
749
750
        if (phdr->p_align > 1 && (phdr->p_align & (phdr->p_align - 1)) != 0) {
751
            panic(true, "elf: p_align is not a power of 2");
752
        }
753
754
        if (phdr->p_align > ret) {
755
            ret = phdr->p_align;
756
        }
757
    }
758
759
    if (ret == 0) {
760
        panic(true, "elf: Executable has no loadable segments");
761
    }
762
763
    return ret;
764
}
765
766
static void elf64_get_ranges(uint8_t *elf, uint64_t slide, struct mem_range **_ranges, uint64_t *_ranges_count) {
767
    struct elf64_hdr *hdr = (void *)elf;
768
769
    uint64_t ranges_count = 0;
770
771
    if (hdr->phdr_size < sizeof(struct elf64_phdr)) {
772
        panic(true, "elf: phdr_size < sizeof(struct elf64_phdr)");
773
    }
774
775
    bool is_reloc = elf64_is_relocatable(elf, hdr);
776
777
    for (uint16_t i = 0; i < hdr->ph_num; i++) {
778
        struct elf64_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
779
780
        if (phdr->p_type != PT_LOAD || phdr->p_memsz == 0) {
781
            continue;
782
        }
783
784
        if (phdr->p_vaddr < FIXED_HIGHER_HALF_OFFSET_64) {
785
            if (!is_reloc) {
786
                continue;
787
            }
788
        }
789
790
        ranges_count++;
791
    }
792
793
    if (ranges_count == 0) {
794
        panic(true, "elf: No higher half PHDRs exist");
795
    }
796
797
    struct mem_range *ranges = ext_mem_alloc_counted(ranges_count, sizeof(struct mem_range));
798
799
    size_t r = 0;
800
    for (uint16_t i = 0; i < hdr->ph_num; i++) {
801
        struct elf64_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
802
803
        if (phdr->p_type != PT_LOAD || phdr->p_memsz == 0) {
804
            continue;
805
        }
806
807
        if (phdr->p_vaddr < FIXED_HIGHER_HALF_OFFSET_64) {
808
            if (!is_reloc) {
809
                continue;
810
            }
811
        }
812
813
        uint64_t load_addr = phdr->p_vaddr + slide;
814
        uint64_t this_top = load_addr + phdr->p_memsz;
815
816
        uint64_t align = phdr->p_align <= 1 ? 1 : phdr->p_align;
817
        ranges[r].base = load_addr & ~(align - 1);
818
        ranges[r].length = ALIGN_UP(this_top - ranges[r].base, align, panic(true, "elf: Alignment overflow"));
819
820
        if (phdr->p_flags & ELF_PF_X) {
821
            ranges[r].permissions |= MEM_RANGE_X;
822
        }
823
824
        if (phdr->p_flags & ELF_PF_W) {
825
            ranges[r].permissions |= MEM_RANGE_W;
826
        }
827
828
        if (phdr->p_flags & ELF_PF_R) {
829
            ranges[r].permissions |= MEM_RANGE_R;
830
        }
831
832
        r++;
833
    }
834
835
    *_ranges_count = ranges_count;
836
    *_ranges = ranges;
837
}
838
839
bool elf64_load(uint8_t *elf, size_t file_size, uint64_t *entry_point, uint64_t *_slide, uint32_t alloc_type, bool kaslr, struct mem_range **ranges, uint64_t *ranges_count, uint64_t *physical_base, uint64_t *virtual_base, uint64_t *_image_size, uint64_t *_image_size_before_bss, bool *is_reloc) {
840
    struct elf64_hdr *hdr = (void *)elf;
841
842
    elf64_validate(hdr);
843
844
    if (hdr->type != ET_EXEC && hdr->type != ET_DYN) {
845
        panic(true, "elf: ELF file not of type ET_EXEC nor ET_DYN");
846
    }
847
848
    if (hdr->phdr_size < sizeof(struct elf64_phdr)) {
849
        panic(true, "elf: phdr_size < sizeof(struct elf64_phdr)");
850
    }
851
852
    uint64_t phdr_table_end = CHECKED_ADD(
853
        CHECKED_MUL((uint64_t)hdr->ph_num, (uint64_t)hdr->phdr_size,
854
            panic(true, "elf: Program header table size overflow")),
855
        hdr->phoff,
856
        panic(true, "elf: Program header table size overflow"));
857
858
    if (phdr_table_end > file_size) {
859
        panic(true, "elf: Program header table extends beyond file bounds");
860
    }
861
862
    if (is_reloc) {
863
        *is_reloc = false;
864
    }
865
    if (elf64_is_relocatable(elf, hdr)) {
866
        if (is_reloc) {
867
            *is_reloc = true;
868
        }
869
    }
870
871
    uint64_t slide = 0;
872
    size_t try_count = 0;
873
    size_t max_simulated_tries = 0x10000;
874
875
    uint64_t entry = hdr->entry;
876
877
    uint64_t max_align = elf64_max_align(elf);
878
879
    uint64_t image_size = 0;
880
881
    bool lower_to_higher = false;
882
883
    uint64_t min_vaddr = (uint64_t)-1;
884
    uint64_t max_vaddr = 0;
885
    for (uint16_t i = 0; i < hdr->ph_num; i++) {
886
        struct elf64_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
887
888
        if (phdr->p_type != PT_LOAD || phdr->p_memsz == 0) {
889
            continue;
890
        }
891
892
        if (phdr->p_vaddr < FIXED_HIGHER_HALF_OFFSET_64) {
893
            if (!is_reloc || !*is_reloc) {
894
                panic(true, "elf: Lower half PHDRs are not allowed");
895
            }
896
            lower_to_higher = true;
897
        } else {
898
            if (lower_to_higher) {
899
                panic(true, "elf: Mix of lower and higher half PHDRs in relocatable kernel");
900
            }
901
        }
902
903
        uint64_t phdr_end = CHECKED_ADD(phdr->p_vaddr, phdr->p_memsz,
904
            panic(true, "elf: p_vaddr + p_memsz overflow in PHDR %u", i));
905
906
        // check for overlapping phdrs
907
        for (uint16_t j = 0; j < hdr->ph_num; j++) {
908
            struct elf64_phdr *phdr_in = (void *)elf + (hdr->phoff + j * hdr->phdr_size);
909
910
            if (phdr_in->p_type != PT_LOAD || phdr_in->p_memsz == 0) {
911
                continue;
912
            }
913
914
            if (phdr_in->p_vaddr < FIXED_HIGHER_HALF_OFFSET_64) {
915
                if (!is_reloc || !*is_reloc) {
916
                    continue;
917
                }
918
            }
919
920
            if (phdr_in == phdr) {
921
                continue;
922
            }
923
924
            uint64_t phdr_in_end = CHECKED_ADD(phdr_in->p_vaddr, phdr_in->p_memsz,
925
                panic(true, "elf: p_vaddr + p_memsz overflow in PHDR %u", j));
926
927
            if ((phdr_in->p_vaddr >= phdr->p_vaddr
928
              && phdr_in->p_vaddr < phdr_end)
929
                ||
930
                (phdr_in_end > phdr->p_vaddr
931
              && phdr_in_end <= phdr_end)) {
932
                panic(true, "elf: Attempted to load ELF file with overlapping PHDRs (%u and %u overlap)", i, j);
933
            }
934
935
            if (ranges != NULL) {
936
                uint64_t page_rounded_base = ALIGN_DOWN(phdr->p_vaddr, 4096);
937
                uint64_t page_rounded_top = ALIGN_UP(phdr_end, 4096, panic(true, "elf: PHDR alignment overflow"));
938
                uint64_t page_rounded_base_in = ALIGN_DOWN(phdr_in->p_vaddr, 4096);
939
                uint64_t page_rounded_top_in = ALIGN_UP(phdr_in_end, 4096, panic(true, "elf: PHDR alignment overflow"));
940
941
                if ((page_rounded_base >= page_rounded_base_in
942
                  && page_rounded_base < page_rounded_top_in)
943
                   ||
944
                    (page_rounded_top > page_rounded_base_in
945
                  && page_rounded_top <= page_rounded_top_in)) {
946
                    if ((phdr->p_flags & 0b111) != (phdr_in->p_flags & 0b111)) {
947
                        panic(true, "elf: Attempted to load ELF file with PHDRs with different permissions sharing the same memory page.");
948
                    }
949
                }
950
            }
951
        }
952
953
        if (phdr->p_vaddr < min_vaddr) {
954
            min_vaddr = phdr->p_vaddr;
955
        }
956
957
        if (phdr_end > max_vaddr) {
958
            max_vaddr = phdr_end;
959
        }
960
    }
961
962
    if (min_vaddr == (uint64_t)-1) {
963
        panic(true, "elf: No usable PHDRs exist");
964
    }
965
966
    if (lower_to_higher) {
967
        slide = FIXED_HIGHER_HALF_OFFSET_64 - min_vaddr;
968
    }
969
970
    image_size = max_vaddr - min_vaddr;
971
972
    *physical_base = (uintptr_t)ext_mem_alloc_type_aligned(image_size, alloc_type, max_align);
973
    *virtual_base = min_vaddr;
974
975
    if (_image_size) {
976
        *_image_size = image_size;
977
    }
978
979
again:
980
    if (is_reloc && *is_reloc && kaslr) {
981
        slide = (rand32() & ~(max_align - 1)) + (lower_to_higher ? FIXED_HIGHER_HALF_OFFSET_64 - min_vaddr : 0);
982
983
        if (*virtual_base + slide + image_size < 0xffffffff80000000 /* this comparison relies on overflow */) {
984
            if (++try_count == max_simulated_tries) {
985
                panic(true, "elf: Image wants to load too high");
986
            }
987
            goto again;
988
        }
989
    }
990
991
    uint64_t bss_size = 0;
992
993
    for (uint16_t i = 0; i < hdr->ph_num; i++) {
994
        struct elf64_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
995
996
        if (phdr->p_type != PT_LOAD || phdr->p_memsz == 0) {
997
            continue;
998
        }
999
1000
        // Sanity checks
1001
        if (phdr->p_filesz > phdr->p_memsz) {
1002
            panic(true, "elf: p_filesz > p_memsz");
1003
        }
1004
1005
        // Validate p_offset + p_filesz doesn't overflow or exceed file size
1006
        uint64_t offset_end = CHECKED_ADD(phdr->p_offset, phdr->p_filesz,
1007
            panic(true, "elf: p_offset + p_filesz overflow"));
1008
        if (offset_end > file_size) {
1009
            panic(true, "elf: p_offset + p_filesz exceeds file size");
1010
        }
1011
1012
        uint64_t load_addr = *physical_base + (phdr->p_vaddr - *virtual_base);
1013
1014
#if defined (__aarch64__)
1015
        uint64_t this_top = CHECKED_ADD(load_addr, phdr->p_memsz,
1016
            panic(true, "elf: load_addr + p_memsz overflow"));
1017
1018
        uint64_t mem_base, mem_size;
1019
1020
        uint64_t align = phdr->p_align <= 1 ? 1 : phdr->p_align;
1021
        mem_base = load_addr & ~(align - 1);
1022
        mem_size = this_top - mem_base;
1023
#endif
1024
1025
        memcpy((void *)(uintptr_t)load_addr, elf + (phdr->p_offset), phdr->p_filesz);
1026
1027
        if (phdr->p_vaddr + phdr->p_memsz == max_vaddr) {
1028
            bss_size = phdr->p_memsz - phdr->p_filesz;
1029
        }
1030
1031
        if (!elf64_apply_relocations(elf, file_size, hdr, (void *)(uintptr_t)load_addr, phdr->p_vaddr, phdr->p_memsz, slide)) {
1032
            panic(true, "elf: Failed to apply relocations");
1033
        }
1034
1035
#if defined (__aarch64__)
1036
        clean_dcache_poc(mem_base, mem_base + mem_size);
1037
        inval_icache_pou(mem_base, mem_base + mem_size);
1038
#endif
1039
    }
1040
1041
    if (_image_size_before_bss != NULL) {
1042
        *_image_size_before_bss = image_size - bss_size;
1043
    }
1044
1045
    *virtual_base += slide;
1046
    *entry_point = entry + slide;
1047
    if (_slide) {
1048
        *_slide = slide;
1049
    }
1050
1051
    if (ranges_count != NULL && ranges != NULL) {
1052
        elf64_get_ranges(elf, slide, ranges, ranges_count);
1053
    }
1054
1055
    return true;
1056
}
1057
1058
bool elf32_load_elsewhere(uint8_t *elf, size_t file_size, uint64_t *entry_point,
1059
                          struct elsewhere_range **ranges) {
1060
    struct elf32_hdr *hdr = (void *)elf;
1061
1062
    elf32_validate(hdr);
1063
1064
    if (hdr->type != ET_EXEC && hdr->type != ET_DYN) {
1065
        panic(true, "elf: ELF file not of type ET_EXEC nor ET_DYN");
1066
    }
1067
1068
    *entry_point = hdr->entry;
1069
    bool entry_adjusted = false;
1070
1071
    if (hdr->phdr_size < sizeof(struct elf32_phdr)) {
1072
        panic(true, "elf: phdr_size < sizeof(struct elf32_phdr)");
1073
    }
1074
1075
    uint64_t phdr_table_size32 = (uint64_t)hdr->ph_num * hdr->phdr_size;
1076
    if (hdr->phoff > file_size || phdr_table_size32 > file_size - hdr->phoff) {
1077
        panic(true, "elf: Program header table extends beyond file bounds");
1078
    }
1079
1080
    uint64_t min_paddr = (uint64_t)-1;
1081
    uint64_t max_paddr = 0;
1082
    bool has_loadable = false;
1083
    for (uint16_t i = 0; i < hdr->ph_num; i++) {
1084
        struct elf32_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
1085
1086
        if (phdr->p_type != PT_LOAD || phdr->p_memsz == 0)
1087
            continue;
1088
1089
        has_loadable = true;
1090
1091
        if (phdr->p_paddr < min_paddr) {
1092
            min_paddr = phdr->p_paddr;
1093
        }
1094
1095
        uint64_t top = CHECKED_ADD((uint64_t)phdr->p_paddr, phdr->p_memsz,
1096
            panic(true, "elf: p_paddr + p_memsz overflow"));
1097
        if (top > max_paddr) {
1098
            max_paddr = top;
1099
        }
1100
    }
1101
    if (!has_loadable) {
1102
        panic(true, "elf: No loadable segments");
1103
    }
1104
    uint64_t image_size_64 = max_paddr - min_paddr;
1105
    if (image_size_64 > SIZE_MAX) {
1106
        panic(true, "elf: Image size exceeds address space");
1107
    }
1108
    size_t image_size = (size_t)image_size_64;
1109
1110
    void *elsewhere = ext_mem_alloc(image_size);
1111
1112
    *ranges = ext_mem_alloc(sizeof(struct elsewhere_range));
1113
1114
    (*ranges)->elsewhere = (uintptr_t)elsewhere;
1115
    (*ranges)->target = min_paddr;
1116
    (*ranges)->length = image_size;
1117
1118
    for (uint16_t i = 0; i < hdr->ph_num; i++) {
1119
        struct elf32_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
1120
1121
        if (phdr->p_type != PT_LOAD || phdr->p_memsz == 0)
1122
            continue;
1123
1124
        // Sanity checks
1125
        if (phdr->p_filesz > phdr->p_memsz) {
1126
            panic(true, "elf: p_filesz > p_memsz");
1127
        }
1128
        uint64_t offset_end = CHECKED_ADD((uint64_t)phdr->p_offset, phdr->p_filesz,
1129
            panic(true, "elf: p_offset + p_filesz overflow"));
1130
        if (offset_end > file_size) {
1131
            panic(true, "elf: p_offset + p_filesz exceeds file size");
1132
        }
1133
1134
        memcpy(elsewhere + (phdr->p_paddr - min_paddr), elf + phdr->p_offset, phdr->p_filesz);
1135
1136
        if (!entry_adjusted
1137
         && *entry_point >= phdr->p_vaddr
1138
         && *entry_point < CHECKED_ADD(phdr->p_vaddr, phdr->p_memsz, continue)) {
1139
            *entry_point -= phdr->p_vaddr;
1140
            *entry_point += phdr->p_paddr;
1141
            entry_adjusted = true;
1142
        }
1143
    }
1144
1145
    return true;
1146
}
1147
1148
bool elf64_load_elsewhere(uint8_t *elf, size_t file_size, uint64_t *entry_point,
1149
                          struct elsewhere_range **ranges) {
1150
    struct elf64_hdr *hdr = (void *)elf;
1151
1152
    elf64_validate(hdr);
1153
1154
    if (hdr->type != ET_EXEC && hdr->type != ET_DYN) {
1155
        panic(true, "elf: ELF file not of type ET_EXEC nor ET_DYN");
1156
    }
1157
1158
    *entry_point = hdr->entry;
1159
    bool entry_adjusted = false;
1160
1161
    if (hdr->phdr_size < sizeof(struct elf64_phdr)) {
1162
        panic(true, "elf: phdr_size < sizeof(struct elf64_phdr)");
1163
    }
1164
1165
    uint64_t phdr_table_size64 = (uint64_t)hdr->ph_num * hdr->phdr_size;
1166
    if (hdr->phoff > file_size || phdr_table_size64 > file_size - hdr->phoff) {
1167
        panic(true, "elf: Program header table extends beyond file bounds");
1168
    }
1169
1170
    uint64_t min_paddr = (uint64_t)-1;
1171
    uint64_t max_paddr = 0;
1172
    bool has_loadable = false;
1173
    for (uint16_t i = 0; i < hdr->ph_num; i++) {
1174
        struct elf64_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
1175
1176
        if (phdr->p_type != PT_LOAD || phdr->p_memsz == 0)
1177
            continue;
1178
1179
        has_loadable = true;
1180
1181
        if (phdr->p_paddr < min_paddr) {
1182
            min_paddr = phdr->p_paddr;
1183
        }
1184
1185
        uint64_t top = CHECKED_ADD(phdr->p_paddr, phdr->p_memsz,
1186
            panic(true, "elf: p_paddr + p_memsz overflow"));
1187
        if (top > max_paddr) {
1188
            max_paddr = top;
1189
        }
1190
    }
1191
    if (!has_loadable) {
1192
        panic(true, "elf: No loadable segments");
1193
    }
1194
    uint64_t image_size = max_paddr - min_paddr;
1195
    if (image_size > SIZE_MAX) {
1196
        panic(true, "elf: Image size exceeds address space");
1197
    }
1198
1199
    void *elsewhere = ext_mem_alloc(image_size);
1200
1201
    *ranges = ext_mem_alloc(sizeof(struct elsewhere_range));
1202
1203
    (*ranges)->elsewhere = (uintptr_t)elsewhere;
1204
    (*ranges)->target = min_paddr;
1205
    (*ranges)->length = image_size;
1206
1207
    for (uint16_t i = 0; i < hdr->ph_num; i++) {
1208
        struct elf64_phdr *phdr = (void *)elf + (hdr->phoff + i * hdr->phdr_size);
1209
1210
        if (phdr->p_type != PT_LOAD || phdr->p_memsz == 0)
1211
            continue;
1212
1213
        // Sanity checks
1214
        if (phdr->p_filesz > phdr->p_memsz) {
1215
            panic(true, "elf: p_filesz > p_memsz");
1216
        }
1217
        uint64_t offset_end = CHECKED_ADD(phdr->p_offset, phdr->p_filesz,
1218
            panic(true, "elf: p_offset + p_filesz overflow"));
1219
        if (offset_end > file_size) {
1220
            panic(true, "elf: p_offset + p_filesz exceeds file size");
1221
        }
1222
1223
        memcpy(elsewhere + (phdr->p_paddr - min_paddr), elf + phdr->p_offset, phdr->p_filesz);
1224
1225
        if (!entry_adjusted
1226
         && *entry_point >= phdr->p_vaddr
1227
         && *entry_point < CHECKED_ADD(phdr->p_vaddr, phdr->p_memsz, continue)) {
1228
            *entry_point -= phdr->p_vaddr;
1229
            *entry_point += phdr->p_paddr;
1230
            entry_adjusted = true;
1231
        }
1232
    }
1233
1234
    return true;
1235
}
tab: 248 wrap: offon