]> git.alrj.org Git - bold.git/blobdiff - data/bold_ibh-x86_64.asm
Add support for actual dynamic linking, with external symbol resolution.
[bold.git] / data / bold_ibh-x86_64.asm
diff --git a/data/bold_ibh-x86_64.asm b/data/bold_ibh-x86_64.asm
new file mode 100644 (file)
index 0000000..5555551
--- /dev/null
@@ -0,0 +1,130 @@
+; Bold - Import by hash for linux/amd64 (elf64-x86-64)
+; © 2009 Amand "alrj" Tihon
+; kate: syntax Intel x86 (NASM);
+
+; 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, [rel _bold__functions_hash]        ; Implicitly zero-extended
+  mov edi, [rel _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]
+
+        inc al                            ; DT_STRTAB == 5
+        cmp [rdx], rax
+        cmove r10, [rdx+8]
+
+        inc al                            ; DT_SYMTAB == 6
+        cmp [rdx], rax
+        cmove r11, [rdx+8]
+
+        ; 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
+        .hash_loop:                       ; over each char
+          xor eax, eax
+          lodsb
+          test al, al
+          jz .hash_end
+
+          sub eax, edx
+          shl edx, 6
+          add eax, edx
+          shl edx, 10
+          add edx, eax
+          jmp 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