loader64.asm 6.27 KB
Newer Older
PoroCYon's avatar
PoroCYon committed
1
2
; vim: set ft=nasm:

3
4
;%define R10_BIAS (0x2B4)
%define R10_BIAS (0x2B4+0x40)
5

PoroCYon's avatar
PoroCYon committed
6
7
8
9
10
11
12
13
14
%include "rtld.inc"

%ifdef ELF_TYPE
[section .text.startup.smol]
%else
; not defined -> debugging!
[section .text]
%endif

15
; r9 : ptrdiff_t glibc_vercompat_extra_hi_field_off
PoroCYon's avatar
PoroCYon committed
16
17
; r10: struct link_map* entry + far correction factor
; r12: struct link_map* entry
18
; r14: struct link_map* root
PoroCYon's avatar
PoroCYon committed
19
; r13: _dl_fini address (reqd by the ABI)
PoroCYon's avatar
PoroCYon committed
20
21
22
23
24
25
26

%ifndef ELF_TYPE
extern _symbols
global _start
_start:
%endif
_smol_start:
PoroCYon's avatar
PoroCYon committed
27
%ifdef USE_DL_FINI
PoroCYon's avatar
PoroCYon committed
28
   xchg r13, rdx ; _dl_fini
PoroCYon's avatar
PoroCYon committed
29
%endif
PoroCYon's avatar
PoroCYon committed
30

PoroCYon's avatar
PoroCYon committed
31
32
%ifdef USE_DT_DEBUG
    mov r12, [rel _DEBUG]
33
    mov r12, [r12 + 8]
PoroCYon's avatar
PoroCYon committed
34
%else
PoroCYon's avatar
PoroCYon committed
35
    mov r12, [rsp -  8]        ; return address of _dl_init
36
37
    mov ebx, dword [r12 - 20] ; decode part of 'mov rdi, [rel _rtld_global]'
    mov r12, [r12 + rbx - 16]  ; ???
PoroCYon's avatar
PoroCYon committed
38
%endif
39
        ; struct link_map* root = r12
PoroCYon's avatar
PoroCYon committed
40
41
%ifdef SKIP_ENTRIES
    mov r12, [r12 + L_NEXT_OFF] ; skip this binary
42
43
;   mov r12, [r12 + L_NEXT_OFF] ; skip the vdso
        ; the second one isn't needed anymore, see code below (.next_link)
44
45
;%elifdef USE_DNLOAD_LOADER
;    mov r12, [r12 + L_NEXT_OFF] ; skip this binary
PoroCYon's avatar
PoroCYon committed
46
47
%endif

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
%ifdef USE_DNLOAD_LOADER
   push _symbols
   push r12
    pop r11
    pop rdi

;.loopme: jmp short .loopme ; debugging
    .next_hash:
            ;
        mov r14d, dword [rdi]
            ; assume it's nonzero
       push r11
        pop r12

        .next_link:
            mov r12, [r12 + L_NEXT_OFF]
                ; ElfW(Dyn)* dyn(rsi) = r12->l_ld
            mov rsi, [r12 + L_LD_OFF]

                ; get strtab off
            .next_dyn:
              lodsq
                cmp al, DT_STRTAB
              lodsq
                jne short .next_dyn

                ; void* addr(rcx) = r12->l_addr
                ; const char* strtab(r9) = lookup(rsi,DT_STRTAB), *symtab_end(r8)=r9;
            mov rcx, [r12 + L_ADDR_OFF]
            cmp rax, rcx
            jge short .noreldynaddr
            add rax, rcx
        .noreldynaddr:
           push rax
           push rax
            pop r8
            pop r9

                ; const ElfW(Sym)* symtab(rdx) = lookup(rsi, DT_SYMTAB);
          lodsq ; SYMTAB d_tag
          lodsq ; SYMTAB d_un.d_ptr
            cmp rax, rcx
            jge short .norelsymaddr
            add rax, rcx
        .norelsymaddr:
           push rax
            pop rdx

        .next_sym:
            mov esi, dword [rdx + ST_NAME_OFF]
            add rsi, r9

           push 33
           push 5381
           push 0
            pop rcx
            pop rax
            pop rbx
        .nexthashiter:
                ; TODO: optimize register usage so that lodsb can be used
            mov cl, byte [rsi]
            inc rsi
             or cl, cl
             jz short .breakhash

           push rdx
            mul ebx
            pop rdx
            add eax, ecx
            jmp short .nexthashiter
        .breakhash:

            cmp r14d, eax
             je short .eq

            add rdx, SYMTAB_SIZE
            cmp rdx, r8
             jl short .next_sym
;          int3
            jmp short .next_link

        .eq:
            mov rax, [rdx + ST_VALUE_OFF]
            add rax, [r12 + L_ADDR_OFF]
          stosq
            cmp word [rdi], 0
            jne short .next_hash

; if USE_DNLOAD_LOADER
%else
138
139
       push _smol_start
       push r12
140
141
       push -1
        pop rcx
142
143
144
        pop rdi
        pop rax
repne scasd ; technically, scasq should be used, but ehhhh
145
        sub rdi, r12
146
147
        sub rdi, LF_ENTRY_OFF+4
       xchg r9, rdi
PoroCYon's avatar
PoroCYon committed
148

149
150
   push _symbols
        ; back up link_map root
151
   push r12
152
153
154
155
    pop r11
    pop rdi

;.loopme: jmp short .loopme ; debugging
156
    .next_hash:
157
158
159
160
161
162
163
        mov r14d, dword [rdi]
            ; assume we need at least one function
;        or al, al
;        jz short .needed_end
        mov r12, r11
;      push r11
       push r14
164
        pop rbx
165
;       pop r12
166
167
168
169
170
171
            ; shift left because we don't want to compare the lowest bit
        shr ebx, 1

        .next_link:
            mov r12, [r12 + L_NEXT_OFF]

172
            lea r10, [r12 + r9 + R10_BIAS]
173
174
175
176
177
178
179
180
181
                ; uint32_t bkt_ind(edx) = hash % entry->l_nbuckets
            xor edx, edx
           push r14
            pop rax
            mov ecx, dword [r10 + LF_NBUCKETS_OFF - R10_BIAS]
            div ecx

                ; uint32_t bucket(edx) = entry->l_gnu_buckets[bkt_ind]
            mov r8 , [r10 + LF_GNU_BUCKETS_OFF - R10_BIAS]
182
            mov ecx, dword [r8 + rdx * 4]
183

184
185
                ; can be ignored apparently?
;         jecxz .next_link
186
187
188

            .next_chain:
                    ; uint32_t luhash(ecx) = entry->l_gnu_chain_zero[bucket] >> 1
189
190
                mov rdx, [r10 + LF_GNU_CHAIN_ZERO_OFF - R10_BIAS]
                mov edx, dword [rdx + rcx * 4]
191

192
193
                    ; TODO: make this not suck. (maybe using bt*?)
                mov al, dl
194

195
                shr edx, 1
196
                    ; if (luhash == hash) break;
197
                cmp edx, ebx
198
199
200
201
202
                 je short .chain_break

                    ; ++bucket; } while (luhash & 1);
                and al, 1
                jnz short .next_link
203
204

                inc ecx
205
                jmp short .next_chain
PoroCYon's avatar
PoroCYon committed
206
207

        .chain_break:
208
209
210
211
212
213
214
215
216
                ; ElfW(Sym)* symtab = entry->l_info[DT_SYMTAB]->d_un.d_ptr
                ; ElfW(Sym)* sym = &symtab[bucket]
                ; *phash = sym->st_value + entry->l_addr

                ; ElfW(Dyn)* dyn(rax) = entry->l_info[DT_SYMTAB]
            mov rax, [r12 + L_INFO_DT_SYMTAB_OFF]
                ; ElfW(Sym)* symtab(rax) = dyn->d_un.d_ptr
            mov rax, [rax + D_UN_PTR_OFF]
                ; ElfW(Addr) symoff(rax) = symtab[bucket].st_value
217
            lea rdx, [rcx + rcx * 2]
218
219
            mov rax, [rax + rdx * 8 + ST_VALUE_OFF]
                ; void* finaladdr(rax) = symoff + entry->l_addr
220
            add rax, [r12 + L_ADDR_OFF]
221
222
223

                ; *phash = finaladdr
          stosq
PoroCYon's avatar
PoroCYon committed
224
            cmp word [rdi], 0
225
            jne short .next_hash
226
            ; } while (1)
227
;       jmp short .next_hash
PoroCYon's avatar
PoroCYon committed
228

229
230
231
; if USE_DNLOAD_LOADER ... else ...
%endif

PoroCYon's avatar
PoroCYon committed
232
.needed_end:
233
234
235
236
;  int3 ; debugging
;   xor rbp, rbp ; still 0 from _dl_start_user
%ifndef NO_START_ARG
        ; arg for _start
PoroCYon's avatar
PoroCYon committed
237
    mov rdi, rsp
238
%endif
239
%ifdef ALIGN_STACK
240
241
242
%ifdef USE_DNLOAD_LOADER
   push rax
%else
PoroCYon's avatar
PoroCYon committed
243
       ; apparently not needed?
244
%endif
245
%endif
PoroCYon's avatar
PoroCYon committed
246
%ifdef USE_DL_FINI
PoroCYon's avatar
PoroCYon committed
247
   xchg rsi, r13 ; _dl_fini
PoroCYon's avatar
PoroCYon committed
248
%endif
PoroCYon's avatar
PoroCYon committed
249
250
        ; fallthru to _start