mirror of https://github.com/Shizmob/smol
157 lines
4.4 KiB
ArmAsm
157 lines
4.4 KiB
ArmAsm
; vim: set ft=nasm ts=8:
|
|
|
|
%define LM_NAME_OFFSET 0x4
|
|
%define LM_NEXT_OFFSET 0xC
|
|
%define LM_ADDR_OFFSET 0
|
|
%define LM_INFO_OFFSET 0x20
|
|
|
|
; by default, use the offset 'correction' from glibc 2.28
|
|
%define LM_ENTRY_OFFSET_BASE 340
|
|
|
|
%define LM_NBUCKETS_OFFSET 0x178
|
|
%define LM_GNU_BUCKETS_OFFSET 0x188
|
|
%define LM_GNU_CHAIN_ZERO_OFFSET 0x18C
|
|
|
|
%define DT_VALUE_OFFSET 0x4
|
|
%define DYN_PTR_OFFSET 0x4
|
|
|
|
%define DT_SYMTAB 0x6
|
|
%define DT_SYMSIZE_SHIFT 4
|
|
|
|
lm_off_extra:
|
|
dd 0
|
|
|
|
[section .text._smol_start]
|
|
|
|
strcmp: ; (const char *s1 (esi), const char *s2 (edi))
|
|
push esi
|
|
push edi
|
|
.cmp: lodsb
|
|
or al, al
|
|
jz .done
|
|
sub al, [edi]
|
|
jnz .done
|
|
inc edi
|
|
jmp .cmp
|
|
.done: pop edi
|
|
pop esi
|
|
ret
|
|
|
|
|
|
basename: ; (const char *s (esi))
|
|
push esi
|
|
push edi
|
|
mov edi, esi
|
|
.cmp: lodsb
|
|
or al, al
|
|
jz .done
|
|
cmp al, 47 ; '/'
|
|
cmove edi, esi
|
|
jmp .cmp
|
|
.done: mov eax, edi
|
|
pop edi
|
|
pop esi
|
|
ret
|
|
|
|
|
|
link_symbol: ; (struct link_map *entry, uint32_t *h)
|
|
mov ecx, esi
|
|
|
|
; eax = *h % entry->l_nbuckets
|
|
mov eax, [ecx]
|
|
xor edx, edx
|
|
mov ebx, [ebp + edi + LM_NBUCKETS_OFFSET]
|
|
div ebx
|
|
; eax = entry->l_gnu_buckets[eax]
|
|
mov eax, [ebp + edi + LM_GNU_BUCKETS_OFFSET]
|
|
mov eax, [eax + edx * 4]
|
|
; *h |= 1
|
|
or word [ecx], 1
|
|
.check_bucket: ; edx = entry->l_gnu_chain_zero[eax] | 1
|
|
mov edx, [ebp + edi + LM_GNU_CHAIN_ZERO_OFFSET]
|
|
mov edx, [edx + eax * 4]
|
|
or edx, 1
|
|
; check if this is our symbol
|
|
cmp edx, [ecx]
|
|
je .found
|
|
inc eax
|
|
jmp .check_bucket
|
|
.found: ; it is! edx = entry->l_info[DT_SYMTAB]->d_un.d_ptr
|
|
mov edx, [ebp + LM_INFO_OFFSET + DT_SYMTAB * 4]
|
|
mov edx, [edx + DYN_PTR_OFFSET]
|
|
; edx = edx[eax].dt_value + entry->l_addr
|
|
shl eax, DT_SYMSIZE_SHIFT
|
|
mov edx, [edx + eax + DT_VALUE_OFFSET]
|
|
add edx, [ebp + LM_ADDR_OFFSET]
|
|
sub edx, ecx
|
|
sub edx, 4
|
|
; finally, write it back!
|
|
mov [ecx], edx
|
|
ret
|
|
|
|
|
|
link: ; (struct link_map *root, char *symtable)
|
|
mov eax, [esp+4]
|
|
mov esi, [esp+8]
|
|
.do_library: ; null library name means end of symbol table, we're done
|
|
cmp byte [esi], 0
|
|
jz .done
|
|
; setup start of map again
|
|
mov ebp, eax
|
|
push eax
|
|
.find_map_entry: ; compare basename(entry->l_name) to lib name, if so we got a match
|
|
push esi
|
|
mov esi, [ebp + LM_NAME_OFFSET]
|
|
call basename
|
|
mov edi, eax
|
|
pop esi
|
|
call strcmp
|
|
jz .process_map_entry
|
|
; no match, next entry it is!
|
|
mov ebp, [ebp + LM_NEXT_OFFSET]
|
|
jmp .find_map_entry
|
|
.process_map_entry: ; skip past the name in the symbol table now to get to the symbols
|
|
lodsb
|
|
or al, al
|
|
jnz .process_map_entry
|
|
|
|
.do_symbols: ; null byte means end of symbols for this library!
|
|
cmp byte [esi], 0
|
|
jz .next_library
|
|
inc esi
|
|
push edi
|
|
mov edi, [lm_off_extra]
|
|
call link_symbol
|
|
pop edi
|
|
add esi, 4
|
|
jmp .do_symbols
|
|
.next_library: pop eax
|
|
inc esi
|
|
jmp .do_library
|
|
.done: ret
|
|
|
|
|
|
extern _start
|
|
_smol_start:
|
|
; try to get the 'version-agnostic' pffset of the stuff we're
|
|
; interested in
|
|
mov ebx, eax
|
|
mov esi, eax
|
|
.looper:
|
|
lodsd
|
|
cmp dword eax, _smol_start
|
|
jne short .looper
|
|
sub esi, ebx
|
|
sub esi, LM_ENTRY_OFFSET_BASE+4 ; +4: take inc-after from lodsb into acct
|
|
mov [lm_off_extra], esi
|
|
|
|
mov eax, ebx
|
|
|
|
push _symbols
|
|
push eax
|
|
call link
|
|
|
|
;jmp short _start
|
|
; by abusing the linker script, _start ends up right here :)
|
|
|