]> git.alrj.org Git - bold.git/blobdiff - runtime/bold_ibh-x86_64.asm
First support for .gnu.hash/DT_GNU_HASH.
[bold.git] / runtime / bold_ibh-x86_64.asm
index 5395cd440fceec25330775fcbe8a914a4611a3c6..f309ce7666b85e66972409485f4d4aa6d054362e 100644 (file)
@@ -9,20 +9,23 @@
 ; 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
-; yasm -f elf64 -o bold_ibh-x86_64.o bold_ibh-x86_64.asm
-; (or replace yasm by nasm)
+; nasm -f elf64 -o bold_ibh-x86_64.o bold_ibh-x86_64.asm
 
 
 BITS 64
 CPU X64
 
-global _bold__ibh
+global _bold__ibh_start
 global exit
 
 extern _dt_debug                        ; defined by bold linker
@@ -36,58 +39,81 @@ extern main                             ; must be declared when using this
 
 segment .text
 
-_bold__ibh:
+_bold__ibh_start:
 ; {{{ 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 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
-  mov ecx, _bold__functions_count
+  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 in eax
+    lodsd                                 ; Load symbol hash
+    xchg ebx, eax                         ; into ebx
     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
+      mov rdx, [r14 + 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
+      .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
-        xor al, al
-        cmp [rdx], rax
-        jnz .dynamic_loop
+        cmp [rdx], dword 0
+        jnz short .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:
+      .symtabloop:
         ; Find the symbol name in strtab
         mov esi, [r11]                    ; st_name, offset in strtab
         add rsi, r10                      ; pointer to symbol name
@@ -103,30 +129,36 @@ _bold__ibh:
           jnz short .hash_loop
 
         .hash_end:
-        cmp edx, r15d                     ; Compare with stored hash
-        je .found
-        add r11, 24                       ; Next symtab entry
-      loop .symbolloop
+        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 r13, [r13 + 24]                 ; Next link_map entry
-      jmp short .libloop
+      mov r14, [r14 + 24]                 ; Next link_map entry
+      jmp .libloop
     .found:
     mov rax, [r11 + 8]                    ; st_value, offset of the symbol
-    add rax, [r13]                        ; add link_map->l_addr
+    add rax, [r14]                        ; add link_map->l_addr
+    stosq                                 ; Store function pointer
 ;   }}}
 
     pop rcx
     pop rsi
-    stosq                               ; Store function pointer
-    loop .symbol_loop
+    ;loop .symbol_loop
+    dec ecx
+    jnz .symbol_loop
 ; }}}
 
   ; When all is resolved, call main()
   call main
-  mov edi, eax
 
 exit:
   ; Exit cleanly
-  mov eax, SYS_exit
+  xchg edi, eax
+  push byte SYS_exit
+  pop rax
   syscall
+
+%assign code_size $ - _bold__ibh_start
+%warning Code size is: code_size