1#include "dynlink.h"
2#include "relr.h"
3#include "libc.h"
4#include <zircon/compiler.h>
5#include <stdatomic.h>
6#include <stddef.h>
7
8#ifdef __clang__
9// TODO(mcgrathr): Really we want to compile just this file without
10// -fsanitize-coverage, but this works around the issue for now.
11__asm__(".weakref __sanitizer_cov_trace_pc_guard, _dlstart_sancov_dummy");
12__asm__(".pushsection .text._dlstart_sancov_dummy,\"ax\",%progbits\n"
13        ".local _dlstart_sancov_dummy\n"
14        ".type _dlstart_sancov_dummy,%function\n"
15        "_dlstart_sancov_dummy: ret\n"
16        ".size _dlstart_sancov_dummy, . - _dlstart_sancov_dummy\n"
17        ".popsection");
18#endif
19
20__LOCAL __NO_SAFESTACK NO_ASAN dl_start_return_t _dl_start(void* start_arg,
21                                                           void* vdso) {
22    ElfW(Addr) base = (uintptr_t)__ehdr_start;
23    const ElfW(Rel)* rel = NULL;
24    const ElfW(Rela)* rela = NULL;
25    const ElfW(Addr)* relr = NULL;
26    size_t relcount = 0, relacount = 0, relrsz = 0;
27
28    // We rely on having been linked with -z combreloc so we get
29    // the DT_REL(A)COUNT tag and relocs are sorted with all the
30    // R_*_RELATIVE cases first.
31
32    for (const ElfW(Dyn)* d = _DYNAMIC; d->d_tag != DT_NULL; ++d) {
33        switch (d->d_tag) {
34        case DT_REL:
35            rel = (const void*)(base + d->d_un.d_ptr);
36            break;
37        case DT_RELA:
38            rela = (const void*)(base + d->d_un.d_ptr);
39            break;
40        case DT_RELR:
41            relr = (const void*)(base + d->d_un.d_ptr);
42            break;
43        case DT_RELCOUNT:
44            relcount = d->d_un.d_val;
45            break;
46        case DT_RELACOUNT:
47            relacount = d->d_un.d_val;
48            break;
49        case DT_RELRSZ:
50            relrsz = d->d_un.d_val;
51            break;
52        case DT_RELRENT:
53            if (d->d_un.d_val != sizeof(relr[0])) {
54                __builtin_trap();
55            }
56            break;
57        }
58    }
59
60    for (size_t i = 0; i < relcount; ++i) {
61        ElfW(Addr)* addr = (uintptr_t*)(base + rel[i].r_offset);
62        // Invariant (no asserts here): R_TYPE(rel[i].r_info) == REL_RELATIVE
63        *addr += base;
64    }
65
66    for (size_t i = 0; i < relacount; ++i) {
67        ElfW(Addr)* addr = (uintptr_t*)(base + rela[i].r_offset);
68        // Invariant (no asserts here): R_TYPE(rela[i].r_info) == REL_RELATIVE
69        *addr = base + rela[i].r_addend;
70    }
71
72    apply_relr(base, relr, relrsz);
73
74    // Make sure all the relocations have landed before calling __dls2,
75    // which relies on them.
76    atomic_signal_fence(memory_order_seq_cst);
77
78    return __dls2(start_arg, vdso);
79}
80