; kate: syntax Intel x86 (NASM); ; Copyright (C) 2009 Amand "alrj" Tihon ; Import by hash for linux/amd64 (elf64-x86-64) ; This file is part of bold, the Byte Optimized Linker. ; You can redistribute this file and/or modify it under the terms of the ; GNU General Public License as published by the Free Software Foundation, ; either version 3 of the License or (at your option) any later version. ; Under Section 7 of GPL version 3, you are granted additional ; permissions described in the Bold Runtime Library Exception, version ; 1.0, as published by Amand Tihon. ;------------------------------------------------------------------------------ ; alrj's x86_64 version of the import by hash method by parapete, las, leblane. ; See the wonderful thread at http://www.pouet.net/topic.php?which=5392 to ; learn everything about import by hash on Linux. ; Compile with ; nasm -f elf64 -o bold_ibh-x86_64.o bold_ibh-x86_64.asm BITS 64 CPU X64 global _bold__ibh_start global exit extern _dt_debug ; defined by bold linker extern _bold__functions_hash ; in .data, generated by bold extern _bold__functions_pointers ; in .bss, generated by bold extern _bold__functions_count ; immediate 32 bits extern main ; must be declared when using this %define SYS_exit 60 %define DT_HASH 4 segment .text _bold__ibh_start: ; {{{ Do the RTLD mov r14, [rel _dt_debug] ; r14 points to r_debug mov r14, [r14 + 8] ; r14 points to link_map mov r14, [r14 + 24] ; skip the first two link_map entries mov r14, [r14 + 24] mov esi, _bold__functions_hash ; Implicitly zero-extended mov edi, _bold__functions_pointers ; ditto push byte _bold__functions_count ; Warning: Max 127 external symbols. pop rcx ; Linker should enforce this. ; Load all the symbols .symbol_loop: lodsd ; Load symbol hash xchg ebx, eax ; into ebx push rsi push rcx ; {{{ For each hash ; Iterate over libraries found in link_map .libloop: mov rdx, [r14 + 16] ; link_map->l_ld ; Find the interesting entries in the DYNAMIC table. .dynamic_loop: mov rsi, [rdx+8] cmp [rdx], dword 4 ; DT_HASH == 4 jne .no_hash ; Why the heck does it segfault when mov ecx, [rsi+4] ; I use cmove ecx, [rsi+4] instead .no_hash: ; of this jne construction ???? cmp [rdx], dword 5 ; DT_STRTAB == 5 cmove r10, rsi ; r10 : pointer to strtab cmp [rdx], dword 6 ; DT_SYMTAB == 6 cmove r11, rsi ; r11 : pointer to symtab cmp [rdx], dword 0x6ffffef5 ; DT_GNU_HASH jne .not_gnu_hash mov ecx, [rsi] ; ecx is nbuckets mov r9d, [rsi + 8] ; maskwords (64 bits entries) lea r9, [rsi + 16 + r9 * 8] ; rdx points to the first bucket xor eax, eax .walk_buckets: ; Find the last chain cmp eax, [r9] cmovl eax, [r9] add r9, 4 ; next bucket loop .walk_buckets ; eax is offset to the last chain ; Now, rdx points to the beginning of the first chain mov ecx, [rsi+4] ; symndx xchg eax, ecx shl rax, 2 ; symndx * 4 sub r9, rax ; hash values - symndx * 4 .walk_chain: bt dword [r9 + rcx*4], 0 ; inc ecx ; Increment ecx for each entry found jc .walk_chain ; in the chain. dec ecx ; fixup. .not_gnu_hash: ; Next dynamic entry add rdx, 16 cmp [rdx], dword 0 jnz short .dynamic_loop ; All DYNAMIC entries have been read. ; Iterate over the symbols in the library (symtab entries). .symtabloop: ; Find the symbol name in strtab mov esi, [r11] ; st_name, offset in strtab add rsi, r10 ; pointer to symbol name ; Compute the hash xor edx, edx xor eax, eax .hash_loop: ; over each char imul edx, edx, byte 0x21 xor edx, eax lodsb test al, al jnz short .hash_loop .hash_end: cmp edx, ebx ; Compare with stored hash je short .found lea r11, [r11 + 24] ; Next symtab entry loop .symtabloop ; Symbol was not found in this library mov r14, [r14 + 24] ; Next link_map entry jmp .libloop .found: mov rax, [r11 + 8] ; st_value, offset of the symbol add rax, [r14] ; add link_map->l_addr stosq ; Store function pointer ; }}} pop rcx pop rsi ;loop .symbol_loop dec ecx jnz .symbol_loop ; }}} ; When all is resolved, call main() call main exit: ; Exit cleanly xchg edi, eax push byte SYS_exit pop rax syscall %assign code_size $ - _bold__ibh_start %warning Code size is: code_size