+; kate: syntax Intel x86 (NASM);
+
+; Copyright (C) 2009 Amand "alrj" Tihon <amand.tihon@alrj.org>
+
+; 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.
+
+;------------------------------------------------------------------------------
+; 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
+; yasm -f elf64 -o bold_ibh-x86_64.o bold_ibh-x86_64.asm
+; (or replace yasm by nasm)
+
+
+BITS 64
+CPU X64
+
+global _bold__ibh
+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:
+; {{{ Do the RTLD
+ mov rbx, [_dt_debug] ; rbx points to r_debug
+ mov rbx, [rbx + 8] ; rbx points to link_map
+ mov rbx, [rbx + 24] ; skip the first two link_map entries
+ mov rbx, [rbx + 24]
+
+ mov esi, _bold__functions_hash ; Implicitly zero-extended
+ mov edi, _bold__functions_pointers ; ditto
+ mov ecx, _bold__functions_count
+
+ ; Load all the symbols
+ .symbol_loop:
+ lodsd ; Load symbol hash in eax
+ push rsi
+ push rcx
+
+; {{{ For each hash
+ mov r15d, eax ; Save function hash
+ mov r13, rbx ; copy link_map's pseudo-head
+
+ ; Iterate over libraries found in link_map
+ .libloop:
+ mov rdx, [r13 + 16] ; link_map->l_ld
+
+ ; Find the interesting entries in the DYNAMIC table.
+ .dynamic_loop:
+ xor eax, eax ; enough because hash was 32 bits
+
+ mov al, DT_HASH ; DT_HASH == 4
+ cmp [rdx], rax
+ cmove r9, [rdx+8] ; r9 : pointer to the hash table
+
+ inc al ; DT_STRTAB == 5
+ cmp [rdx], rax
+ cmove r10, [rdx+8] ; r10 : pointer to strtab
+
+ inc al ; DT_SYMTAB == 6
+ cmp [rdx], rax
+ cmove r11, [rdx+8] ; r11 : pointer to symtab
+
+ ; Next dynamic entry
+ add rdx, 16
+ xor al, al
+ cmp [rdx], rax
+ jnz .dynamic_loop
+
+ ; All DYNAMIC entries have been read.
+ mov ecx, [r9 + 4] ; nchain, number of exported symbols
+
+ ; Iterate over the symbols in the library (symtab entries).
+ .symbolloop:
+ ; 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, r15d ; Compare with stored hash
+ je .found
+ add r11, 24 ; Next symtab entry
+ loop .symbolloop
+
+ ; Symbol was not found in this library
+ mov r13, [r13 + 24] ; Next link_map entry
+ jmp short .libloop
+ .found:
+ mov rax, [r11 + 8] ; st_value, offset of the symbol
+ add rax, [r13] ; add link_map->l_addr
+; }}}
+
+ pop rcx
+ pop rsi
+ stosq ; Store function pointer
+ loop .symbol_loop
+; }}}
+
+ ; When all is resolved, call main()
+ call main
+ mov edi, eax
+
+exit:
+ ; Exit cleanly
+ mov eax, SYS_exit
+ syscall