]>
Commit | Line | Data |
---|---|---|
82b216b8 PS |
1 | 2006-07-10 Jakub Jelinek <jakub@redhat.com> |
2 | ||
3 | include/ | |
4 | * bfdlink.h (struct bfd_link_info): Add emit_hash and | |
5 | emit_gnu_hash bitfields. | |
6 | include/elf/ | |
7 | * common.h (SHT_GNU_HASH, DT_GNU_HASH): Define. | |
8 | bfd/ | |
9 | * elf.c (_bfd_elf_print_private_bfd_data): Handle DT_GNU_HASH. | |
10 | (bfd_section_from_shdr, elf_fake_sections, assign_section_numbers): | |
11 | Handle SHT_GNU_HASH. | |
12 | (special_sections_g): Include .gnu.hash section. | |
13 | (bfd_elf_gnu_hash): New function. | |
14 | * elf-bfd.h (bfd_elf_gnu_hash, _bfd_elf_hash_symbol): New prototypes. | |
15 | (struct elf_backend_data): Add elf_hash_symbol method. | |
16 | * elflink.c (_bfd_elf_link_create_dynamic_sections): Create .hash | |
17 | only if info->emit_hash, create .gnu.hash section if | |
18 | info->emit_gnu_hash. | |
19 | (struct collect_gnu_hash_codes): New type. | |
20 | (elf_collect_gnu_hash_codes, elf_renumber_gnu_hash_syms, | |
21 | _bfd_elf_hash_symbol): New functions. | |
22 | (compute_bucket_count): Don't compute HASHCODES array, instead add | |
23 | that and NSYMS as arguments. Use bed->s->sizeof_hash_entry | |
24 | instead of bed->s->arch_size / 8. Fix .hash size estimation. | |
25 | When not optimizing, use the number of hashed symbols rather than | |
26 | dynsymcount. | |
27 | (bfd_elf_size_dynamic_sections): Only add DT_HASH if info->emit_hash, | |
28 | and ADD DT_GNU_HASH if info->emit_gnu_hash. | |
29 | (bfd_elf_size_dynsym_hash_dynstr): Size .hash only if info->emit_hash, | |
30 | adjust compute_bucket_count caller. Create and populate .gnu.hash | |
31 | section if info->emit_gnu_hash. | |
32 | (elf_link_output_extsym): Only populate .hash section if | |
33 | finfo->hash_sec != NULL. | |
34 | (bfd_elf_final_link): Adjust assertion. Handle DT_GNU_HASH. | |
35 | * elfxx-target.h (elf_backend_hash_symbol): Define if not yet defined. | |
36 | (elfNN_bed): Add elf_backend_hash_symbol. | |
37 | * elf64-x86-64.c (elf64_x86_64_hash_symbol): New function. | |
38 | (elf_backend_hash_symbol): Define. | |
39 | * elf32-i386.c (elf_i386_hash_symbol): New function. | |
40 | (elf_backend_hash_symbol): Define. | |
41 | ||
42 | Index: gdb-6.5/bfd/elf-bfd.h | |
43 | =================================================================== | |
44 | --- gdb-6.5.orig/bfd/elf-bfd.h 2006-07-14 01:30:51.000000000 -0300 | |
45 | +++ gdb-6.5/bfd/elf-bfd.h 2006-07-14 01:31:25.000000000 -0300 | |
46 | @@ -1022,6 +1022,9 @@ struct elf_backend_data | |
47 | bfd_boolean *, bfd_boolean *, | |
48 | bfd *, asection **); | |
49 | ||
50 | + /* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ | |
51 | + bfd_boolean (*elf_hash_symbol) (struct elf_link_hash_entry *); | |
52 | + | |
53 | /* Used to handle bad SHF_LINK_ORDER input. */ | |
54 | bfd_error_handler_type link_order_error_handler; | |
55 | ||
56 | @@ -1462,6 +1465,8 @@ extern bfd_vma _bfd_elf_section_offset | |
57 | ||
58 | extern unsigned long bfd_elf_hash | |
59 | (const char *); | |
60 | +extern unsigned long bfd_elf_gnu_hash | |
61 | + (const char *); | |
62 | ||
63 | extern bfd_reloc_status_type bfd_elf_generic_reloc | |
64 | (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); | |
65 | @@ -1632,6 +1637,8 @@ extern bfd_boolean _bfd_elf_merge_symbol | |
66 | struct elf_link_hash_entry **, bfd_boolean *, | |
67 | bfd_boolean *, bfd_boolean *, bfd_boolean *); | |
68 | ||
69 | +extern bfd_boolean _bfd_elf_hash_symbol (struct elf_link_hash_entry *); | |
70 | + | |
71 | extern bfd_boolean _bfd_elf_add_default_symbol | |
72 | (bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, | |
73 | const char *, Elf_Internal_Sym *, asection **, bfd_vma *, | |
74 | Index: gdb-6.5/bfd/elf64-x86-64.c | |
75 | =================================================================== | |
76 | --- gdb-6.5.orig/bfd/elf64-x86-64.c 2006-07-14 01:30:51.000000000 -0300 | |
77 | +++ gdb-6.5/bfd/elf64-x86-64.c 2006-07-14 01:31:26.000000000 -0300 | |
78 | @@ -3614,6 +3614,19 @@ elf64_x86_64_additional_program_headers | |
79 | return count; | |
80 | } | |
81 | ||
82 | +/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ | |
83 | + | |
84 | +static bfd_boolean | |
85 | +elf64_x86_64_hash_symbol (struct elf_link_hash_entry *h) | |
86 | +{ | |
87 | + if (h->plt.offset != (bfd_vma) -1 | |
88 | + && !h->def_regular | |
89 | + && !h->pointer_equality_needed) | |
90 | + return FALSE; | |
91 | + | |
92 | + return _bfd_elf_hash_symbol (h); | |
93 | +} | |
94 | + | |
95 | static const struct bfd_elf_special_section | |
96 | elf64_x86_64_special_sections[]= | |
97 | { | |
98 | @@ -3685,5 +3698,7 @@ static const struct bfd_elf_special_sect | |
99 | elf64_x86_64_special_sections | |
100 | #define elf_backend_additional_program_headers \ | |
101 | elf64_x86_64_additional_program_headers | |
102 | +#define elf_backend_hash_symbol \ | |
103 | + elf64_x86_64_hash_symbol | |
104 | ||
105 | #include "elf64-target.h" | |
106 | Index: gdb-6.5/bfd/elf.c | |
107 | =================================================================== | |
108 | --- gdb-6.5.orig/bfd/elf.c 2006-07-14 01:30:51.000000000 -0300 | |
109 | +++ gdb-6.5/bfd/elf.c 2006-07-14 01:31:26.000000000 -0300 | |
110 | @@ -206,6 +206,21 @@ bfd_elf_hash (const char *namearg) | |
111 | return h & 0xffffffff; | |
112 | } | |
113 | ||
114 | +/* DT_GNU_HASH hash function. Do not change this function; you will | |
115 | + cause invalid hash tables to be generated. */ | |
116 | + | |
117 | +unsigned long | |
118 | +bfd_elf_gnu_hash (const char *namearg) | |
119 | +{ | |
120 | + const unsigned char *name = (const unsigned char *) namearg; | |
121 | + unsigned long h = 5381; | |
122 | + unsigned char ch; | |
123 | + | |
124 | + while ((ch = *name++) != '\0') | |
125 | + h = (h << 5) + h + ch; | |
126 | + return h & 0xffffffff; | |
127 | +} | |
128 | + | |
129 | bfd_boolean | |
130 | bfd_elf_mkobject (bfd *abfd) | |
131 | { | |
132 | @@ -1239,6 +1254,7 @@ _bfd_elf_print_private_bfd_data (bfd *ab | |
133 | case DT_AUXILIARY: name = "AUXILIARY"; stringp = TRUE; break; | |
134 | case DT_USED: name = "USED"; break; | |
135 | case DT_FILTER: name = "FILTER"; stringp = TRUE; break; | |
136 | + case DT_GNU_HASH: name = "GNU_HASH"; break; | |
137 | } | |
138 | ||
139 | fprintf (f, " %-11s ", name); | |
140 | @@ -1822,6 +1838,7 @@ bfd_section_from_shdr (bfd *abfd, unsign | |
141 | case SHT_FINI_ARRAY: /* .fini_array section. */ | |
142 | case SHT_PREINIT_ARRAY: /* .preinit_array section. */ | |
143 | case SHT_GNU_LIBLIST: /* .gnu.liblist section. */ | |
144 | + case SHT_GNU_HASH: /* .gnu.hash section. */ | |
145 | return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); | |
146 | ||
147 | case SHT_DYNAMIC: /* Dynamic linking information. */ | |
148 | @@ -2294,6 +2311,7 @@ static const struct bfd_elf_special_sect | |
149 | { ".gnu.version_r", 14, 0, SHT_GNU_verneed, 0 }, | |
150 | { ".gnu.liblist", 12, 0, SHT_GNU_LIBLIST, SHF_ALLOC }, | |
151 | { ".gnu.conflict", 13, 0, SHT_RELA, SHF_ALLOC }, | |
152 | + { ".gnu.hash", 9, 0, SHT_GNU_HASH, SHF_ALLOC }, | |
153 | { NULL, 0, 0, 0, 0 } | |
154 | }; | |
155 | ||
156 | @@ -2810,6 +2828,10 @@ elf_fake_sections (bfd *abfd, asection * | |
157 | case SHT_GROUP: | |
158 | this_hdr->sh_entsize = 4; | |
159 | break; | |
160 | + | |
161 | + case SHT_GNU_HASH: | |
162 | + this_hdr->sh_entsize = bed->s->arch_size == 64 ? 0 : 4; | |
163 | + break; | |
164 | } | |
165 | ||
166 | if ((asect->flags & SEC_ALLOC) != 0) | |
167 | @@ -3255,6 +3277,7 @@ assign_section_numbers (bfd *abfd, struc | |
168 | break; | |
169 | ||
170 | case SHT_HASH: | |
171 | + case SHT_GNU_HASH: | |
172 | case SHT_GNU_versym: | |
173 | /* sh_link is the section header index of the symbol table | |
174 | this hash table or version table is for. */ | |
175 | Index: gdb-6.5/bfd/elf32-i386.c | |
176 | =================================================================== | |
177 | --- gdb-6.5.orig/bfd/elf32-i386.c 2006-07-14 01:30:51.000000000 -0300 | |
178 | +++ gdb-6.5/bfd/elf32-i386.c 2006-07-14 01:31:26.000000000 -0300 | |
179 | @@ -3872,6 +3872,18 @@ elf_i386_plt_sym_val (bfd_vma i, const a | |
180 | return plt->vma + (i + 1) * PLT_ENTRY_SIZE; | |
181 | } | |
182 | ||
183 | +/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ | |
184 | + | |
185 | +static bfd_boolean | |
186 | +elf_i386_hash_symbol (struct elf_link_hash_entry *h) | |
187 | +{ | |
188 | + if (h->plt.offset != (bfd_vma) -1 | |
189 | + && !h->def_regular | |
190 | + && !h->pointer_equality_needed) | |
191 | + return FALSE; | |
192 | + | |
193 | + return _bfd_elf_hash_symbol (h); | |
194 | +} | |
195 | ||
196 | #define TARGET_LITTLE_SYM bfd_elf32_i386_vec | |
197 | #define TARGET_LITTLE_NAME "elf32-i386" | |
198 | @@ -3912,6 +3924,7 @@ elf_i386_plt_sym_val (bfd_vma i, const a | |
199 | #define elf_backend_size_dynamic_sections elf_i386_size_dynamic_sections | |
200 | #define elf_backend_always_size_sections elf_i386_always_size_sections | |
201 | #define elf_backend_plt_sym_val elf_i386_plt_sym_val | |
202 | +#define elf_backend_hash_symbol elf_i386_hash_symbol | |
203 | ||
204 | #include "elf32-target.h" | |
205 | ||
206 | Index: gdb-6.5/bfd/elflink.c | |
207 | =================================================================== | |
208 | --- gdb-6.5.orig/bfd/elflink.c 2006-07-14 01:30:51.000000000 -0300 | |
209 | +++ gdb-6.5/bfd/elflink.c 2006-07-14 01:31:26.000000000 -0300 | |
210 | @@ -240,12 +240,30 @@ _bfd_elf_link_create_dynamic_sections (b | |
211 | if (!_bfd_elf_define_linkage_sym (abfd, info, s, "_DYNAMIC")) | |
212 | return FALSE; | |
213 | ||
214 | - s = bfd_make_section_with_flags (abfd, ".hash", | |
215 | - flags | SEC_READONLY); | |
216 | - if (s == NULL | |
217 | - || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) | |
218 | - return FALSE; | |
219 | - elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry; | |
220 | + if (info->emit_hash) | |
221 | + { | |
222 | + s = bfd_make_section_with_flags (abfd, ".hash", flags | SEC_READONLY); | |
223 | + if (s == NULL | |
224 | + || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) | |
225 | + return FALSE; | |
226 | + elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry; | |
227 | + } | |
228 | + | |
229 | + if (info->emit_gnu_hash) | |
230 | + { | |
231 | + s = bfd_make_section_with_flags (abfd, ".gnu.hash", | |
232 | + flags | SEC_READONLY); | |
233 | + if (s == NULL | |
234 | + || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) | |
235 | + return FALSE; | |
236 | + /* For 64-bit ELF, .gnu.hash is a non-uniform entity size section: | |
237 | + 4 32-bit words followed by variable count of 64-bit words, then | |
238 | + variable count of 32-bit words. */ | |
239 | + if (bed->s->arch_size == 64) | |
240 | + elf_section_data (s)->this_hdr.sh_entsize = 0; | |
241 | + else | |
242 | + elf_section_data (s)->this_hdr.sh_entsize = 4; | |
243 | + } | |
244 | ||
245 | /* Let the backend create the rest of the sections. This lets the | |
246 | backend set the right flags. The backend will normally create | |
247 | @@ -4795,6 +4813,131 @@ elf_collect_hash_codes (struct elf_link_ | |
248 | return TRUE; | |
249 | } | |
250 | ||
251 | +struct collect_gnu_hash_codes | |
252 | +{ | |
253 | + bfd *output_bfd; | |
254 | + const struct elf_backend_data *bed; | |
255 | + unsigned long int nsyms; | |
256 | + unsigned long int maskbits; | |
257 | + unsigned long int *hashcodes; | |
258 | + unsigned long int *hashval; | |
259 | + unsigned long int *indx; | |
260 | + unsigned long int *counts; | |
261 | + bfd_vma *bitmask; | |
262 | + bfd_byte *contents; | |
263 | + long int min_dynindx; | |
264 | + unsigned long int bucketcount; | |
265 | + unsigned long int symindx; | |
266 | + long int local_indx; | |
267 | + long int shift1, shift2; | |
268 | + unsigned long int mask; | |
269 | +}; | |
270 | + | |
271 | +/* This function will be called though elf_link_hash_traverse to store | |
272 | + all hash value of the exported symbols in an array. */ | |
273 | + | |
274 | +static bfd_boolean | |
275 | +elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data) | |
276 | +{ | |
277 | + struct collect_gnu_hash_codes *s = data; | |
278 | + const char *name; | |
279 | + char *p; | |
280 | + unsigned long ha; | |
281 | + char *alc = NULL; | |
282 | + | |
283 | + if (h->root.type == bfd_link_hash_warning) | |
284 | + h = (struct elf_link_hash_entry *) h->root.u.i.link; | |
285 | + | |
286 | + /* Ignore indirect symbols. These are added by the versioning code. */ | |
287 | + if (h->dynindx == -1) | |
288 | + return TRUE; | |
289 | + | |
290 | + /* Ignore also local symbols and undefined symbols. */ | |
291 | + if (! (*s->bed->elf_hash_symbol) (h)) | |
292 | + return TRUE; | |
293 | + | |
294 | + name = h->root.root.string; | |
295 | + p = strchr (name, ELF_VER_CHR); | |
296 | + if (p != NULL) | |
297 | + { | |
298 | + alc = bfd_malloc (p - name + 1); | |
299 | + memcpy (alc, name, p - name); | |
300 | + alc[p - name] = '\0'; | |
301 | + name = alc; | |
302 | + } | |
303 | + | |
304 | + /* Compute the hash value. */ | |
305 | + ha = bfd_elf_gnu_hash (name); | |
306 | + | |
307 | + /* Store the found hash value in the array for compute_bucket_count, | |
308 | + and also for .dynsym reordering purposes. */ | |
309 | + s->hashcodes[s->nsyms] = ha; | |
310 | + s->hashval[h->dynindx] = ha; | |
311 | + ++s->nsyms; | |
312 | + if (s->min_dynindx < 0 || s->min_dynindx > h->dynindx) | |
313 | + s->min_dynindx = h->dynindx; | |
314 | + | |
315 | + if (alc != NULL) | |
316 | + free (alc); | |
317 | + | |
318 | + return TRUE; | |
319 | +} | |
320 | + | |
321 | +/* This function will be called though elf_link_hash_traverse to do | |
322 | + final dynaminc symbol renumbering. */ | |
323 | + | |
324 | +static bfd_boolean | |
325 | +elf_renumber_gnu_hash_syms (struct elf_link_hash_entry *h, void *data) | |
326 | +{ | |
327 | + struct collect_gnu_hash_codes *s = data; | |
328 | + unsigned long int bucket; | |
329 | + unsigned long int val; | |
330 | + | |
331 | + if (h->root.type == bfd_link_hash_warning) | |
332 | + h = (struct elf_link_hash_entry *) h->root.u.i.link; | |
333 | + | |
334 | + /* Ignore indirect symbols. */ | |
335 | + if (h->dynindx == -1) | |
336 | + return TRUE; | |
337 | + | |
338 | + /* Ignore also local symbols and undefined symbols. */ | |
339 | + if (! (*s->bed->elf_hash_symbol) (h)) | |
340 | + { | |
341 | + if (h->dynindx >= s->min_dynindx) | |
342 | + h->dynindx = s->local_indx++; | |
343 | + return TRUE; | |
344 | + } | |
345 | + | |
346 | + bucket = s->hashval[h->dynindx] % s->bucketcount; | |
347 | + val = (s->hashval[h->dynindx] >> s->shift1) | |
348 | + & ((s->maskbits >> s->shift1) - 1); | |
349 | + s->bitmask[val] |= ((bfd_vma) 1) << (s->hashval[h->dynindx] & s->mask); | |
350 | + s->bitmask[val] | |
351 | + |= ((bfd_vma) 1) << ((s->hashval[h->dynindx] >> s->shift2) & s->mask); | |
352 | + val = s->hashval[h->dynindx] & ~(unsigned long int) 1; | |
353 | + if (s->counts[bucket] == 1) | |
354 | + /* Last element terminates the chain. */ | |
355 | + val |= 1; | |
356 | + bfd_put_32 (s->output_bfd, val, | |
357 | + s->contents + (s->indx[bucket] - s->symindx) * 4); | |
358 | + --s->counts[bucket]; | |
359 | + h->dynindx = s->indx[bucket]++; | |
360 | + return TRUE; | |
361 | +} | |
362 | + | |
363 | +/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ | |
364 | + | |
365 | +bfd_boolean | |
366 | +_bfd_elf_hash_symbol (struct elf_link_hash_entry *h) | |
367 | +{ | |
368 | + return !(h->forced_local | |
369 | + || h->root.type == bfd_link_hash_undefined | |
370 | + || h->root.type == bfd_link_hash_undefweak | |
371 | + || ((h->root.type == bfd_link_hash_defined | |
372 | + || h->root.type == bfd_link_hash_defweak) | |
373 | + && h->root.u.def.section->output_section == NULL)); | |
374 | +} | |
375 | + | |
376 | /* Array used to determine the number of hash table buckets to use | |
377 | based on the number of symbols there are. If there are fewer than | |
378 | 3 symbols we use 1 bucket, fewer than 17 symbols we use 3 buckets, | |
379 | @@ -4816,42 +4959,26 @@ static const size_t elf_buckets[] = | |
380 | Therefore the result is always a good payoff between few collisions | |
381 | (= short chain lengths) and table size. */ | |
382 | static size_t | |
383 | -compute_bucket_count (struct bfd_link_info *info) | |
384 | +compute_bucket_count (struct bfd_link_info *info, unsigned long int *hashcodes, | |
385 | + unsigned long int nsyms, int gnu_hash) | |
386 | { | |
387 | size_t dynsymcount = elf_hash_table (info)->dynsymcount; | |
388 | size_t best_size = 0; | |
389 | - unsigned long int *hashcodes; | |
390 | - unsigned long int *hashcodesp; | |
391 | unsigned long int i; | |
392 | bfd_size_type amt; | |
393 | ||
394 | - /* Compute the hash values for all exported symbols. At the same | |
395 | - time store the values in an array so that we could use them for | |
396 | - optimizations. */ | |
397 | - amt = dynsymcount; | |
398 | - amt *= sizeof (unsigned long int); | |
399 | - hashcodes = bfd_malloc (amt); | |
400 | - if (hashcodes == NULL) | |
401 | - return 0; | |
402 | - hashcodesp = hashcodes; | |
403 | - | |
404 | - /* Put all hash values in HASHCODES. */ | |
405 | - elf_link_hash_traverse (elf_hash_table (info), | |
406 | - elf_collect_hash_codes, &hashcodesp); | |
407 | - | |
408 | /* We have a problem here. The following code to optimize the table | |
409 | size requires an integer type with more the 32 bits. If | |
410 | BFD_HOST_U_64_BIT is set we know about such a type. */ | |
411 | #ifdef BFD_HOST_U_64_BIT | |
412 | if (info->optimize) | |
413 | { | |
414 | - unsigned long int nsyms = hashcodesp - hashcodes; | |
415 | size_t minsize; | |
416 | size_t maxsize; | |
417 | BFD_HOST_U_64_BIT best_chlen = ~((BFD_HOST_U_64_BIT) 0); | |
418 | - unsigned long int *counts ; | |
419 | bfd *dynobj = elf_hash_table (info)->dynobj; | |
420 | const struct elf_backend_data *bed = get_elf_backend_data (dynobj); | |
421 | + unsigned long int *counts; | |
422 | ||
423 | /* Possible optimization parameters: if we have NSYMS symbols we say | |
424 | that the hashing table must at least have NSYMS/4 and at most | |
425 | @@ -4860,6 +4987,13 @@ compute_bucket_count (struct bfd_link_in | |
426 | if (minsize == 0) | |
427 | minsize = 1; | |
428 | best_size = maxsize = nsyms * 2; | |
429 | + if (gnu_hash) | |
430 | + { | |
431 | + if (minsize < 2) | |
432 | + minsize = 2; | |
433 | + if ((best_size & 31) == 0) | |
434 | + ++best_size; | |
435 | + } | |
436 | ||
437 | /* Create array where we count the collisions in. We must use bfd_malloc | |
438 | since the size could be large. */ | |
439 | @@ -4867,10 +5001,7 @@ compute_bucket_count (struct bfd_link_in | |
440 | amt *= sizeof (unsigned long int); | |
441 | counts = bfd_malloc (amt); | |
442 | if (counts == NULL) | |
443 | - { | |
444 | - free (hashcodes); | |
445 | - return 0; | |
446 | - } | |
447 | + return 0; | |
448 | ||
449 | /* Compute the "optimal" size for the hash table. The criteria is a | |
450 | minimal chain length. The minor criteria is (of course) the size | |
451 | @@ -4882,6 +5013,9 @@ compute_bucket_count (struct bfd_link_in | |
452 | unsigned long int j; | |
453 | unsigned long int fact; | |
454 | ||
455 | + if (gnu_hash && (i & 31) == 0) | |
456 | + continue; | |
457 | + | |
458 | memset (counts, '\0', i * sizeof (unsigned long int)); | |
459 | ||
460 | /* Determine how often each hash bucket is used. */ | |
461 | @@ -4897,9 +5031,9 @@ compute_bucket_count (struct bfd_link_in | |
462 | # define BFD_TARGET_PAGESIZE (4096) | |
463 | # endif | |
464 | ||
465 | - /* We in any case need 2 + NSYMS entries for the size values and | |
466 | - the chains. */ | |
467 | - max = (2 + nsyms) * (bed->s->arch_size / 8); | |
468 | + /* We in any case need 2 + DYNSYMCOUNT entries for the size values | |
469 | + and the chains. */ | |
470 | + max = (2 + dynsymcount) * bed->s->sizeof_hash_entry; | |
471 | ||
472 | # if 1 | |
473 | /* Variant 1: optimize for short chains. We add the squares | |
474 | @@ -4909,7 +5043,7 @@ compute_bucket_count (struct bfd_link_in | |
475 | max += counts[j] * counts[j]; | |
476 | ||
477 | /* This adds penalties for the overall size of the table. */ | |
478 | - fact = i / (BFD_TARGET_PAGESIZE / (bed->s->arch_size / 8)) + 1; | |
479 | + fact = i / (BFD_TARGET_PAGESIZE / bed->s->sizeof_hash_entry) + 1; | |
480 | max *= fact * fact; | |
481 | # else | |
482 | /* Variant 2: Optimize a lot more for small table. Here we | |
483 | @@ -4920,7 +5054,7 @@ compute_bucket_count (struct bfd_link_in | |
484 | ||
485 | /* The overall size of the table is considered, but not as | |
486 | strong as in variant 1, where it is squared. */ | |
487 | - fact = i / (BFD_TARGET_PAGESIZE / (bed->s->arch_size / 8)) + 1; | |
488 | + fact = i / (BFD_TARGET_PAGESIZE / bed->s->sizeof_hash_entry) + 1; | |
489 | max *= fact; | |
490 | # endif | |
491 | ||
492 | @@ -4943,14 +5077,13 @@ compute_bucket_count (struct bfd_link_in | |
493 | for (i = 0; elf_buckets[i] != 0; i++) | |
494 | { | |
495 | best_size = elf_buckets[i]; | |
496 | - if (dynsymcount < elf_buckets[i + 1]) | |
497 | + if (nsyms < elf_buckets[i + 1]) | |
498 | break; | |
499 | } | |
500 | + if (gnu_hash && best_size < 2) | |
501 | + best_size = 2; | |
502 | } | |
503 | ||
504 | - /* Free the arrays we needed. */ | |
505 | - free (hashcodes); | |
506 | - | |
507 | return best_size; | |
508 | } | |
509 | ||
510 | @@ -5308,7 +5441,10 @@ bfd_elf_size_dynamic_sections (bfd *outp | |
511 | bfd_size_type strsize; | |
512 | ||
513 | strsize = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr); | |
514 | - if (!_bfd_elf_add_dynamic_entry (info, DT_HASH, 0) | |
515 | + if ((info->emit_hash | |
516 | + && !_bfd_elf_add_dynamic_entry (info, DT_HASH, 0)) | |
517 | + || (info->emit_gnu_hash | |
518 | + && !_bfd_elf_add_dynamic_entry (info, DT_GNU_HASH, 0)) | |
519 | || !_bfd_elf_add_dynamic_entry (info, DT_STRTAB, 0) | |
520 | || !_bfd_elf_add_dynamic_entry (info, DT_SYMTAB, 0) | |
521 | || !_bfd_elf_add_dynamic_entry (info, DT_STRSZ, strsize) | |
522 | @@ -5710,8 +5846,6 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *ou | |
523 | asection *s; | |
524 | bfd_size_type dynsymcount; | |
525 | unsigned long section_sym_count; | |
526 | - size_t bucketcount = 0; | |
527 | - size_t hash_entry_size; | |
528 | unsigned int dtagcount; | |
529 | ||
530 | dynobj = elf_hash_table (info)->dynobj; | |
531 | @@ -5762,23 +5896,215 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *ou | |
532 | memset (s->contents, 0, section_sym_count * bed->s->sizeof_sym); | |
533 | } | |
534 | ||
535 | + elf_hash_table (info)->bucketcount = 0; | |
536 | + | |
537 | /* Compute the size of the hashing table. As a side effect this | |
538 | computes the hash values for all the names we export. */ | |
539 | - bucketcount = compute_bucket_count (info); | |
540 | + if (info->emit_hash) | |
541 | + { | |
542 | + unsigned long int *hashcodes; | |
543 | + unsigned long int *hashcodesp; | |
544 | + bfd_size_type amt; | |
545 | + unsigned long int nsyms; | |
546 | + size_t bucketcount; | |
547 | + size_t hash_entry_size; | |
548 | + | |
549 | + /* Compute the hash values for all exported symbols. At the same | |
550 | + time store the values in an array so that we could use them for | |
551 | + optimizations. */ | |
552 | + amt = dynsymcount * sizeof (unsigned long int); | |
553 | + hashcodes = bfd_malloc (amt); | |
554 | + if (hashcodes == NULL) | |
555 | + return FALSE; | |
556 | + hashcodesp = hashcodes; | |
557 | ||
558 | - s = bfd_get_section_by_name (dynobj, ".hash"); | |
559 | - BFD_ASSERT (s != NULL); | |
560 | - hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize; | |
561 | - s->size = ((2 + bucketcount + dynsymcount) * hash_entry_size); | |
562 | - s->contents = bfd_zalloc (output_bfd, s->size); | |
563 | - if (s->contents == NULL) | |
564 | - return FALSE; | |
565 | + /* Put all hash values in HASHCODES. */ | |
566 | + elf_link_hash_traverse (elf_hash_table (info), | |
567 | + elf_collect_hash_codes, &hashcodesp); | |
568 | ||
569 | - bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents); | |
570 | - bfd_put (8 * hash_entry_size, output_bfd, dynsymcount, | |
571 | - s->contents + hash_entry_size); | |
572 | + nsyms = hashcodesp - hashcodes; | |
573 | + bucketcount | |
574 | + = compute_bucket_count (info, hashcodes, nsyms, 0); | |
575 | + free (hashcodes); | |
576 | ||
577 | - elf_hash_table (info)->bucketcount = bucketcount; | |
578 | + if (bucketcount == 0) | |
579 | + return FALSE; | |
580 | + | |
581 | + elf_hash_table (info)->bucketcount = bucketcount; | |
582 | + | |
583 | + s = bfd_get_section_by_name (dynobj, ".hash"); | |
584 | + BFD_ASSERT (s != NULL); | |
585 | + hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize; | |
586 | + s->size = ((2 + bucketcount + dynsymcount) * hash_entry_size); | |
587 | + s->contents = bfd_zalloc (output_bfd, s->size); | |
588 | + if (s->contents == NULL) | |
589 | + return FALSE; | |
590 | + | |
591 | + bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents); | |
592 | + bfd_put (8 * hash_entry_size, output_bfd, dynsymcount, | |
593 | + s->contents + hash_entry_size); | |
594 | + } | |
595 | + | |
596 | + if (info->emit_gnu_hash) | |
597 | + { | |
598 | + size_t i, cnt; | |
599 | + unsigned char *contents; | |
600 | + struct collect_gnu_hash_codes cinfo; | |
601 | + bfd_size_type amt; | |
602 | + size_t bucketcount; | |
603 | + | |
604 | + memset (&cinfo, 0, sizeof (cinfo)); | |
605 | + | |
606 | + /* Compute the hash values for all exported symbols. At the same | |
607 | + time store the values in an array so that we could use them for | |
608 | + optimizations. */ | |
609 | + amt = dynsymcount * 2 * sizeof (unsigned long int); | |
610 | + cinfo.hashcodes = bfd_malloc (amt); | |
611 | + if (cinfo.hashcodes == NULL) | |
612 | + return FALSE; | |
613 | + | |
614 | + cinfo.hashval = cinfo.hashcodes + dynsymcount; | |
615 | + cinfo.min_dynindx = -1; | |
616 | + cinfo.output_bfd = output_bfd; | |
617 | + cinfo.bed = bed; | |
618 | + | |
619 | + /* Put all hash values in HASHCODES. */ | |
620 | + elf_link_hash_traverse (elf_hash_table (info), | |
621 | + elf_collect_gnu_hash_codes, &cinfo); | |
622 | + | |
623 | + bucketcount | |
624 | + = compute_bucket_count (info, cinfo.hashcodes, cinfo.nsyms, 1); | |
625 | + | |
626 | + if (bucketcount == 0) | |
627 | + { | |
628 | + free (cinfo.hashcodes); | |
629 | + return FALSE; | |
630 | + } | |
631 | + | |
632 | + s = bfd_get_section_by_name (dynobj, ".gnu.hash"); | |
633 | + BFD_ASSERT (s != NULL); | |
634 | + | |
635 | + if (cinfo.nsyms == 0) | |
636 | + { | |
637 | + /* Empty .gnu.hash section is special. */ | |
638 | + BFD_ASSERT (cinfo.min_dynindx == -1); | |
639 | + free (cinfo.hashcodes); | |
640 | + s->size = 5 * 4 + bed->s->arch_size / 8; | |
641 | + contents = bfd_zalloc (output_bfd, s->size); | |
642 | + if (contents == NULL) | |
643 | + return FALSE; | |
644 | + s->contents = contents; | |
645 | + /* 1 empty bucket. */ | |
646 | + bfd_put_32 (output_bfd, 1, contents); | |
647 | + /* SYMIDX above the special symbol 0. */ | |
648 | + bfd_put_32 (output_bfd, 1, contents + 4); | |
649 | + /* Just one word for bitmask. */ | |
650 | + bfd_put_32 (output_bfd, 1, contents + 8); | |
651 | + /* Only hash fn bloom filter. */ | |
652 | + bfd_put_32 (output_bfd, 0, contents + 12); | |
653 | + /* No hashes are valid - empty bitmask. */ | |
654 | + bfd_put (bed->s->arch_size, output_bfd, 0, contents + 16); | |
655 | + /* No hashes in the only bucket. */ | |
656 | + bfd_put_32 (output_bfd, 0, | |
657 | + contents + 16 + bed->s->arch_size / 8); | |
658 | + } | |
659 | + else | |
660 | + { | |
661 | + BFD_ASSERT (cinfo.min_dynindx != -1); | |
662 | + unsigned long int maskwords, maskbitslog2; | |
663 | + | |
664 | + maskbitslog2 = bfd_log2 (cinfo.nsyms) + 1; | |
665 | + if (maskbitslog2 < 3) | |
666 | + maskbitslog2 = 5; | |
667 | + else if ((1 << (maskbitslog2 - 2)) & cinfo.nsyms) | |
668 | + maskbitslog2 = maskbitslog2 + 3; | |
669 | + else | |
670 | + maskbitslog2 = maskbitslog2 + 2; | |
671 | + if (bed->s->arch_size == 64) | |
672 | + { | |
673 | + if (maskbitslog2 == 5) | |
674 | + maskbitslog2 = 6; | |
675 | + cinfo.shift1 = 6; | |
676 | + } | |
677 | + else | |
678 | + cinfo.shift1 = 5; | |
679 | + cinfo.mask = (1 << cinfo.shift1) - 1; | |
680 | + cinfo.shift2 = maskbitslog2 + cinfo.shift1; | |
681 | + cinfo.maskbits = 1 << maskbitslog2; | |
682 | + maskwords = 1 << (maskbitslog2 - cinfo.shift1); | |
683 | + amt = bucketcount * sizeof (unsigned long int) * 2; | |
684 | + amt += maskwords * sizeof (bfd_vma); | |
685 | + cinfo.bitmask = bfd_malloc (amt); | |
686 | + if (cinfo.bitmask == NULL) | |
687 | + { | |
688 | + free (cinfo.hashcodes); | |
689 | + return FALSE; | |
690 | + } | |
691 | + | |
692 | + cinfo.counts = (void *) (cinfo.bitmask + maskwords); | |
693 | + cinfo.indx = cinfo.counts + bucketcount; | |
694 | + cinfo.symindx = dynsymcount - cinfo.nsyms; | |
695 | + memset (cinfo.bitmask, 0, maskwords * sizeof (bfd_vma)); | |
696 | + | |
697 | + /* Determine how often each hash bucket is used. */ | |
698 | + memset (cinfo.counts, 0, bucketcount * sizeof (cinfo.counts[0])); | |
699 | + for (i = 0; i < cinfo.nsyms; ++i) | |
700 | + ++cinfo.counts[cinfo.hashcodes[i] % bucketcount]; | |
701 | + | |
702 | + for (i = 0, cnt = cinfo.symindx; i < bucketcount; ++i) | |
703 | + if (cinfo.counts[i] != 0) | |
704 | + { | |
705 | + cinfo.indx[i] = cnt; | |
706 | + cnt += cinfo.counts[i]; | |
707 | + } | |
708 | + BFD_ASSERT (cnt == dynsymcount); | |
709 | + cinfo.bucketcount = bucketcount; | |
710 | + cinfo.local_indx = cinfo.min_dynindx; | |
711 | + | |
712 | + s->size = (4 + bucketcount + cinfo.nsyms) * 4; | |
713 | + s->size += cinfo.maskbits / 8; | |
714 | + contents = bfd_zalloc (output_bfd, s->size); | |
715 | + if (contents == NULL) | |
716 | + { | |
717 | + free (cinfo.bitmask); | |
718 | + free (cinfo.hashcodes); | |
719 | + return FALSE; | |
720 | + } | |
721 | + | |
722 | + s->contents = contents; | |
723 | + bfd_put_32 (output_bfd, bucketcount, contents); | |
724 | + bfd_put_32 (output_bfd, cinfo.symindx, contents + 4); | |
725 | + bfd_put_32 (output_bfd, maskwords, contents + 8); | |
726 | + bfd_put_32 (output_bfd, cinfo.shift2, contents + 12); | |
727 | + contents += 16 + cinfo.maskbits / 8; | |
728 | + | |
729 | + for (i = 0; i < bucketcount; ++i) | |
730 | + { | |
731 | + if (cinfo.counts[i] == 0) | |
732 | + bfd_put_32 (output_bfd, 0, contents); | |
733 | + else | |
734 | + bfd_put_32 (output_bfd, cinfo.indx[i], contents); | |
735 | + contents += 4; | |
736 | + } | |
737 | + | |
738 | + cinfo.contents = contents; | |
739 | + | |
740 | + /* Renumber dynamic symbols, populate .gnu.hash section. */ | |
741 | + elf_link_hash_traverse (elf_hash_table (info), | |
742 | + elf_renumber_gnu_hash_syms, &cinfo); | |
743 | + | |
744 | + contents = s->contents + 16; | |
745 | + for (i = 0; i < maskwords; ++i) | |
746 | + { | |
747 | + bfd_put (bed->s->arch_size, output_bfd, cinfo.bitmask[i], | |
748 | + contents); | |
749 | + contents += bed->s->arch_size / 8; | |
750 | + } | |
751 | + | |
752 | + free (cinfo.bitmask); | |
753 | + free (cinfo.hashcodes); | |
754 | + } | |
755 | + } | |
756 | ||
757 | s = bfd_get_section_by_name (dynobj, ".dynstr"); | |
758 | BFD_ASSERT (s != NULL); | |
759 | @@ -6647,9 +6973,6 @@ elf_link_output_extsym (struct elf_link_ | |
760 | { | |
761 | size_t bucketcount; | |
762 | size_t bucket; | |
763 | - size_t hash_entry_size; | |
764 | - bfd_byte *bucketpos; | |
765 | - bfd_vma chain; | |
766 | bfd_byte *esym; | |
767 | ||
768 | sym.st_name = h->dynstr_index; | |
769 | @@ -6663,15 +6986,23 @@ elf_link_output_extsym (struct elf_link_ | |
770 | ||
771 | bucketcount = elf_hash_table (finfo->info)->bucketcount; | |
772 | bucket = h->u.elf_hash_value % bucketcount; | |
773 | - hash_entry_size | |
774 | - = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize; | |
775 | - bucketpos = ((bfd_byte *) finfo->hash_sec->contents | |
776 | - + (bucket + 2) * hash_entry_size); | |
777 | - chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos); | |
778 | - bfd_put (8 * hash_entry_size, finfo->output_bfd, h->dynindx, bucketpos); | |
779 | - bfd_put (8 * hash_entry_size, finfo->output_bfd, chain, | |
780 | - ((bfd_byte *) finfo->hash_sec->contents | |
781 | - + (bucketcount + 2 + h->dynindx) * hash_entry_size)); | |
782 | + | |
783 | + if (finfo->hash_sec != NULL) | |
784 | + { | |
785 | + size_t hash_entry_size; | |
786 | + bfd_byte *bucketpos; | |
787 | + bfd_vma chain; | |
788 | + | |
789 | + hash_entry_size | |
790 | + = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize; | |
791 | + bucketpos = ((bfd_byte *) finfo->hash_sec->contents | |
792 | + + (bucket + 2) * hash_entry_size); | |
793 | + chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos); | |
794 | + bfd_put (8 * hash_entry_size, finfo->output_bfd, h->dynindx, bucketpos); | |
795 | + bfd_put (8 * hash_entry_size, finfo->output_bfd, chain, | |
796 | + ((bfd_byte *) finfo->hash_sec->contents | |
797 | + + (bucketcount + 2 + h->dynindx) * hash_entry_size)); | |
798 | + } | |
799 | ||
800 | if (finfo->symver_sec != NULL && finfo->symver_sec->contents != NULL) | |
801 | { | |
802 | @@ -7845,7 +8176,7 @@ bfd_elf_final_link (bfd *abfd, struct bf | |
803 | { | |
804 | finfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym"); | |
805 | finfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash"); | |
806 | - BFD_ASSERT (finfo.dynsym_sec != NULL && finfo.hash_sec != NULL); | |
807 | + BFD_ASSERT (finfo.dynsym_sec != NULL); | |
808 | finfo.symver_sec = bfd_get_section_by_name (dynobj, ".gnu.version"); | |
809 | /* Note that it is OK if symver_sec is NULL. */ | |
810 | } | |
811 | @@ -8591,6 +8922,9 @@ bfd_elf_final_link (bfd *abfd, struct bf | |
812 | case DT_HASH: | |
813 | name = ".hash"; | |
814 | goto get_vma; | |
815 | + case DT_GNU_HASH: | |
816 | + name = ".gnu.hash"; | |
817 | + goto get_vma; | |
818 | case DT_STRTAB: | |
819 | name = ".dynstr"; | |
820 | goto get_vma; | |
821 | Index: gdb-6.5/bfd/elfxx-target.h | |
822 | =================================================================== | |
823 | --- gdb-6.5.orig/bfd/elfxx-target.h 2006-07-14 01:30:51.000000000 -0300 | |
824 | +++ gdb-6.5/bfd/elfxx-target.h 2006-07-14 01:31:26.000000000 -0300 | |
825 | @@ -553,6 +553,10 @@ | |
826 | #define elf_backend_merge_symbol NULL | |
827 | #endif | |
828 | ||
829 | +#ifndef elf_backend_hash_symbol | |
830 | +#define elf_backend_hash_symbol _bfd_elf_hash_symbol | |
831 | +#endif | |
832 | + | |
833 | extern const struct elf_size_info _bfd_elfNN_size_info; | |
834 | ||
835 | #ifndef INCLUDED_TARGET_FILE | |
836 | @@ -630,6 +634,7 @@ static const struct elf_backend_data elf | |
837 | elf_backend_common_section_index, | |
838 | elf_backend_common_section, | |
839 | elf_backend_merge_symbol, | |
840 | + elf_backend_hash_symbol, | |
841 | elf_backend_link_order_error_handler, | |
842 | elf_backend_relplt_name, | |
843 | ELF_MACHINE_ALT1, | |
844 | Index: gdb-6.5/include/elf/common.h | |
845 | =================================================================== | |
846 | --- gdb-6.5.orig/include/elf/common.h 2006-07-14 01:30:51.000000000 -0300 | |
847 | +++ gdb-6.5/include/elf/common.h 2006-07-14 01:31:26.000000000 -0300 | |
848 | @@ -338,6 +338,7 @@ | |
849 | #define SHT_LOOS 0x60000000 /* First of OS specific semantics */ | |
850 | #define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ | |
851 | ||
852 | +#define SHT_GNU_HASH 0x6ffffff6 /* GNU style symbol hash table */ | |
853 | #define SHT_GNU_LIBLIST 0x6ffffff7 /* List of prelink dependencies */ | |
854 | ||
855 | /* The next three section types are defined by Solaris, and are named | |
856 | @@ -577,6 +578,7 @@ | |
857 | #define DT_VALRNGHI 0x6ffffdff | |
858 | ||
859 | #define DT_ADDRRNGLO 0x6ffffe00 | |
860 | +#define DT_GNU_HASH 0x6ffffef5 | |
861 | #define DT_TLSDESC_PLT 0x6ffffef6 | |
862 | #define DT_TLSDESC_GOT 0x6ffffef7 | |
863 | #define DT_GNU_CONFLICT 0x6ffffef8 | |
864 | Index: gdb-6.5/include/bfdlink.h | |
865 | =================================================================== | |
866 | --- gdb-6.5.orig/include/bfdlink.h 2006-04-06 15:52:45.000000000 -0300 | |
867 | +++ gdb-6.5/include/bfdlink.h 2006-07-14 01:31:26.000000000 -0300 | |
868 | @@ -324,6 +324,12 @@ struct bfd_link_info | |
869 | /* TRUE if unreferenced sections should be removed. */ | |
870 | unsigned int gc_sections: 1; | |
871 | ||
872 | + /* TRUE if .hash section should be created. */ | |
873 | + unsigned int emit_hash: 1; | |
874 | + | |
875 | + /* TRUE if .gnu.hash section should be created. */ | |
876 | + unsigned int emit_gnu_hash: 1; | |
877 | + | |
878 | /* What to do with unresolved symbols in an object file. | |
879 | When producing executables the default is GENERATE_ERROR. | |
880 | When producing shared libraries the default is IGNORE. The |