@@ -53,6 +53,7 @@ static struct vdso_info
5353 /* Symbol table */
5454 ELF (Sym ) * symtab ;
5555 const char * symstrings ;
56+ ELF (Word ) * gnu_hash ;
5657 ELF_HASH_ENTRY * bucket , * chain ;
5758 ELF_HASH_ENTRY nbucket , nchain ;
5859
@@ -81,6 +82,16 @@ static unsigned long elf_hash(const char *name)
8182 return h ;
8283}
8384
85+ static uint32_t gnu_hash (const char * name )
86+ {
87+ const unsigned char * s = (void * )name ;
88+ uint32_t h = 5381 ;
89+
90+ for (; * s ; s ++ )
91+ h += h * 32 + * s ;
92+ return h ;
93+ }
94+
8495void vdso_init_from_sysinfo_ehdr (uintptr_t base )
8596{
8697 size_t i ;
@@ -123,6 +134,7 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base)
123134 */
124135 ELF_HASH_ENTRY * hash = 0 ;
125136 vdso_info .symstrings = 0 ;
137+ vdso_info .gnu_hash = 0 ;
126138 vdso_info .symtab = 0 ;
127139 vdso_info .versym = 0 ;
128140 vdso_info .verdef = 0 ;
@@ -143,6 +155,11 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base)
143155 ((uintptr_t )dyn [i ].d_un .d_ptr
144156 + vdso_info .load_offset );
145157 break ;
158+ case DT_GNU_HASH :
159+ vdso_info .gnu_hash =
160+ (ELF (Word ) * )((uintptr_t )dyn [i ].d_un .d_ptr +
161+ vdso_info .load_offset );
162+ break ;
146163 case DT_VERSYM :
147164 vdso_info .versym = (ELF (Versym ) * )
148165 ((uintptr_t )dyn [i ].d_un .d_ptr
@@ -155,17 +172,27 @@ void vdso_init_from_sysinfo_ehdr(uintptr_t base)
155172 break ;
156173 }
157174 }
158- if (!vdso_info .symstrings || !vdso_info .symtab || !hash )
175+ if (!vdso_info .symstrings || !vdso_info .symtab ||
176+ (!hash && !vdso_info .gnu_hash ))
159177 return ; /* Failed */
160178
161179 if (!vdso_info .verdef )
162180 vdso_info .versym = 0 ;
163181
164182 /* Parse the hash table header. */
165- vdso_info .nbucket = hash [0 ];
166- vdso_info .nchain = hash [1 ];
167- vdso_info .bucket = & hash [2 ];
168- vdso_info .chain = & hash [vdso_info .nbucket + 2 ];
183+ if (vdso_info .gnu_hash ) {
184+ vdso_info .nbucket = vdso_info .gnu_hash [0 ];
185+ /* The bucket array is located after the header (4 uint32) and the bloom
186+ * filter (size_t array of gnu_hash[2] elements).
187+ */
188+ vdso_info .bucket = vdso_info .gnu_hash + 4 +
189+ sizeof (size_t ) / 4 * vdso_info .gnu_hash [2 ];
190+ } else {
191+ vdso_info .nbucket = hash [0 ];
192+ vdso_info .nchain = hash [1 ];
193+ vdso_info .bucket = & hash [2 ];
194+ vdso_info .chain = & hash [vdso_info .nbucket + 2 ];
195+ }
169196
170197 /* That's all we need. */
171198 vdso_info .valid = true;
@@ -209,36 +236,63 @@ static bool vdso_match_version(ELF(Versym) ver,
209236 && !strcmp (name , vdso_info .symstrings + aux -> vda_name );
210237}
211238
239+ static bool check_sym (ELF (Sym ) * sym , ELF (Word ) i , const char * name ,
240+ const char * version , unsigned long ver_hash )
241+ {
242+ /* Check for a defined global or weak function w/ right name. */
243+ if (ELF64_ST_TYPE (sym -> st_info ) != STT_FUNC )
244+ return false;
245+ if (ELF64_ST_BIND (sym -> st_info ) != STB_GLOBAL &&
246+ ELF64_ST_BIND (sym -> st_info ) != STB_WEAK )
247+ return false;
248+ if (strcmp (name , vdso_info .symstrings + sym -> st_name ))
249+ return false;
250+
251+ /* Check symbol version. */
252+ if (vdso_info .versym &&
253+ !vdso_match_version (vdso_info .versym [i ], version , ver_hash ))
254+ return false;
255+
256+ return true;
257+ }
258+
212259void * vdso_sym (const char * version , const char * name )
213260{
214261 unsigned long ver_hash ;
215262 if (!vdso_info .valid )
216263 return 0 ;
217264
218265 ver_hash = elf_hash (version );
219- ELF (Word ) chain = vdso_info .bucket [elf_hash (name ) % vdso_info .nbucket ];
220-
221- for (; chain != STN_UNDEF ; chain = vdso_info .chain [chain ]) {
222- ELF (Sym ) * sym = & vdso_info .symtab [chain ];
223-
224- /* Check for a defined global or weak function w/ right name. */
225- if (ELF64_ST_TYPE (sym -> st_info ) != STT_FUNC )
226- continue ;
227- if (ELF64_ST_BIND (sym -> st_info ) != STB_GLOBAL &&
228- ELF64_ST_BIND (sym -> st_info ) != STB_WEAK )
229- continue ;
230- if (sym -> st_shndx == SHN_UNDEF )
231- continue ;
232- if (strcmp (name , vdso_info .symstrings + sym -> st_name ))
233- continue ;
234-
235- /* Check symbol version. */
236- if (vdso_info .versym
237- && !vdso_match_version (vdso_info .versym [chain ],
238- version , ver_hash ))
239- continue ;
240-
241- return (void * )(vdso_info .load_offset + sym -> st_value );
266+ ELF (Word ) i ;
267+
268+ if (vdso_info .gnu_hash ) {
269+ uint32_t h1 = gnu_hash (name ), h2 , * hashval ;
270+
271+ i = vdso_info .bucket [h1 % vdso_info .nbucket ];
272+ if (i == 0 )
273+ return 0 ;
274+ h1 |= 1 ;
275+ hashval = vdso_info .bucket + vdso_info .nbucket +
276+ (i - vdso_info .gnu_hash [1 ]);
277+ for (;; i ++ ) {
278+ ELF (Sym ) * sym = & vdso_info .symtab [i ];
279+ h2 = * hashval ++ ;
280+ if (h1 == (h2 | 1 ) &&
281+ check_sym (sym , i , name , version , ver_hash ))
282+ return (void * )(vdso_info .load_offset +
283+ sym -> st_value );
284+ if (h2 & 1 )
285+ break ;
286+ }
287+ } else {
288+ i = vdso_info .bucket [elf_hash (name ) % vdso_info .nbucket ];
289+ for (; i ; i = vdso_info .chain [i ]) {
290+ ELF (Sym ) * sym = & vdso_info .symtab [i ];
291+ if (sym -> st_shndx != SHN_UNDEF &&
292+ check_sym (sym , i , name , version , ver_hash ))
293+ return (void * )(vdso_info .load_offset +
294+ sym -> st_value );
295+ }
242296 }
243297
244298 return 0 ;
0 commit comments