]> git.alrj.org Git - bold.git/blob - runtime/bold_ibh-x86_64.asm
First support for .gnu.hash/DT_GNU_HASH.
[bold.git] / runtime / bold_ibh-x86_64.asm
1 ; kate: syntax Intel x86 (NASM);
2
3 ; Copyright (C) 2009 Amand "alrj" Tihon <amand.tihon@alrj.org>
4
5 ; Import by hash for linux/amd64 (elf64-x86-64)
6 ; This file is part of bold, the Byte Optimized Linker.
7
8 ; You can redistribute this file and/or modify it under the terms of the
9 ; GNU General Public License as published by the Free Software Foundation,
10 ; either version 3 of the License or (at your option) any later version.
11
12 ; Under Section 7 of GPL version 3, you are granted additional
13 ; permissions described in the Bold Runtime Library Exception, version
14 ; 1.0, as published by Amand Tihon.
15
16 ;------------------------------------------------------------------------------
17 ; alrj's x86_64 version of the import by hash method by parapete, las, leblane.
18 ; See the wonderful thread at http://www.pouet.net/topic.php?which=5392 to
19 ; learn everything about import by hash on Linux.
20
21 ; Compile with
22 ; nasm -f elf64 -o bold_ibh-x86_64.o bold_ibh-x86_64.asm
23
24
25 BITS 64
26 CPU X64
27
28 global _bold__ibh_start
29 global exit
30
31 extern _dt_debug                        ; defined by bold linker
32 extern _bold__functions_hash            ; in .data, generated by bold
33 extern _bold__functions_pointers        ; in .bss, generated by bold
34 extern _bold__functions_count           ; immediate 32 bits
35 extern main                             ; must be declared when using this
36
37 %define SYS_exit      60
38 %define DT_HASH       4
39
40 segment .text
41
42 _bold__ibh_start:
43 ; {{{ Do the RTLD
44   mov r14, [rel _dt_debug]              ; r14 points to r_debug
45   mov r14, [r14 + 8]                    ; r14 points to link_map
46   mov r14, [r14 + 24]                   ; skip the first two link_map entries
47   mov r14, [r14 + 24]
48
49   mov esi, _bold__functions_hash        ; Implicitly zero-extended
50   mov edi, _bold__functions_pointers    ; ditto
51   push byte _bold__functions_count      ; Warning: Max 127 external symbols.
52   pop rcx                               ;  Linker should enforce this.
53
54   ; Load all the symbols
55   .symbol_loop:
56     lodsd                                 ; Load symbol hash
57     xchg ebx, eax                         ; into ebx
58     push rsi
59     push rcx
60
61 ;   {{{ For each hash
62
63     ; Iterate over libraries found in link_map
64     .libloop:
65       mov rdx, [r14 + 16]                 ; link_map->l_ld
66
67       ; Find the interesting entries in the DYNAMIC table.
68
69       .dynamic_loop:
70         mov rsi, [rdx+8]
71
72         cmp [rdx], dword 4                ; DT_HASH == 4
73         jne .no_hash                      ; Why the heck does it segfault when
74           mov ecx, [rsi+4]                ; I use cmove ecx, [rsi+4] instead
75         .no_hash:                         ; of this jne construction ????
76
77         cmp [rdx], dword 5                ; DT_STRTAB == 5
78         cmove r10, rsi                    ; r10 : pointer to strtab
79
80         cmp [rdx], dword 6                ; DT_SYMTAB == 6
81         cmove r11, rsi                    ; r11 : pointer to symtab
82
83         cmp [rdx], dword 0x6ffffef5       ; DT_GNU_HASH
84         jne .not_gnu_hash
85           mov ecx, [rsi]                  ; ecx is nbuckets
86           mov r9d, [rsi + 8]              ; maskwords (64 bits entries)
87           lea r9, [rsi + 16 + r9 * 8]     ; rdx points to the first bucket
88
89           xor eax, eax
90           .walk_buckets:                  ; Find the last chain
91             cmp eax, [r9]
92             cmovl eax, [r9]
93             add r9, 4                     ; next bucket
94             loop .walk_buckets            ; eax is offset to the last chain
95           ; Now, rdx points to the beginning of the first chain
96
97           mov ecx, [rsi+4]                ; symndx
98           xchg eax, ecx
99           shl rax, 2                      ; symndx * 4
100           sub r9, rax                     ; hash values - symndx * 4
101           .walk_chain:
102             bt dword [r9 + rcx*4], 0      ;
103             inc ecx                       ; Increment ecx for each entry found
104             jc .walk_chain                ; in the chain.
105           dec ecx                         ; fixup.
106         .not_gnu_hash:
107
108         ; Next dynamic entry
109         add rdx, 16
110         cmp [rdx], dword 0
111         jnz short .dynamic_loop
112
113       ; All DYNAMIC entries have been read.
114
115       ; Iterate over the symbols in the library (symtab entries).
116       .symtabloop:
117         ; Find the symbol name in strtab
118         mov esi, [r11]                    ; st_name, offset in strtab
119         add rsi, r10                      ; pointer to symbol name
120
121         ; Compute the hash
122         xor edx, edx
123         xor eax, eax
124         .hash_loop:                       ; over each char
125           imul edx, edx, byte 0x21
126           xor edx, eax
127           lodsb
128           test al, al
129           jnz short .hash_loop
130
131         .hash_end:
132         cmp edx, ebx                      ; Compare with stored hash
133         je short .found
134         lea r11, [r11 + 24]               ; Next symtab entry
135       loop .symtabloop
136
137       ; Symbol was not found in this library
138       mov r14, [r14 + 24]                 ; Next link_map entry
139       jmp .libloop
140     .found:
141     mov rax, [r11 + 8]                    ; st_value, offset of the symbol
142     add rax, [r14]                        ; add link_map->l_addr
143     stosq                                 ; Store function pointer
144 ;   }}}
145
146     pop rcx
147     pop rsi
148     ;loop .symbol_loop
149     dec ecx
150     jnz .symbol_loop
151 ; }}}
152
153   ; When all is resolved, call main()
154   call main
155
156 exit:
157   ; Exit cleanly
158   xchg edi, eax
159   push byte SYS_exit
160   pop rax
161   syscall
162
163 %assign code_size $ - _bold__ibh_start
164 %warning Code size is: code_size