1a1ba9ba4Schristos /* SEC_MERGE support.
2*184b2d41Schristos Copyright (C) 2001-2020 Free Software Foundation, Inc.
3a1ba9ba4Schristos Written by Jakub Jelinek <jakub@redhat.com>.
4a1ba9ba4Schristos
5a1ba9ba4Schristos This file is part of BFD, the Binary File Descriptor library.
6a1ba9ba4Schristos
7a1ba9ba4Schristos This program is free software; you can redistribute it and/or modify
8a1ba9ba4Schristos it under the terms of the GNU General Public License as published by
9a1ba9ba4Schristos the Free Software Foundation; either version 3 of the License, or
10a1ba9ba4Schristos (at your option) any later version.
11a1ba9ba4Schristos
12a1ba9ba4Schristos This program is distributed in the hope that it will be useful,
13a1ba9ba4Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
14a1ba9ba4Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15a1ba9ba4Schristos GNU General Public License for more details.
16a1ba9ba4Schristos
17a1ba9ba4Schristos You should have received a copy of the GNU General Public License
18a1ba9ba4Schristos along with this program; if not, write to the Free Software
19a1ba9ba4Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20a1ba9ba4Schristos MA 02110-1301, USA. */
21a1ba9ba4Schristos
22a1ba9ba4Schristos
23a1ba9ba4Schristos /* This file contains support for merging duplicate entities within sections,
24a1ba9ba4Schristos as used in ELF SHF_MERGE. */
25a1ba9ba4Schristos
26a1ba9ba4Schristos #include "sysdep.h"
27051580eeSchristos #include <limits.h>
28a1ba9ba4Schristos #include "bfd.h"
29a1ba9ba4Schristos #include "elf-bfd.h"
30a1ba9ba4Schristos #include "libbfd.h"
31a1ba9ba4Schristos #include "hashtab.h"
32a1ba9ba4Schristos #include "libiberty.h"
33a1ba9ba4Schristos
34a1ba9ba4Schristos struct sec_merge_sec_info;
35a1ba9ba4Schristos
36a1ba9ba4Schristos /* An entry in the section merge hash table. */
37a1ba9ba4Schristos
38a1ba9ba4Schristos struct sec_merge_hash_entry
39a1ba9ba4Schristos {
40a1ba9ba4Schristos struct bfd_hash_entry root;
41a1ba9ba4Schristos /* Length of this entry. This includes the zero terminator. */
42a1ba9ba4Schristos unsigned int len;
43a1ba9ba4Schristos /* Start of this string needs to be aligned to
44a1ba9ba4Schristos alignment octets (not 1 << align). */
45a1ba9ba4Schristos unsigned int alignment;
46a1ba9ba4Schristos union
47a1ba9ba4Schristos {
48a1ba9ba4Schristos /* Index within the merged section. */
49a1ba9ba4Schristos bfd_size_type index;
50a1ba9ba4Schristos /* Entry this is a suffix of (if alignment is 0). */
51a1ba9ba4Schristos struct sec_merge_hash_entry *suffix;
52a1ba9ba4Schristos } u;
53a1ba9ba4Schristos /* Which section is it in. */
54a1ba9ba4Schristos struct sec_merge_sec_info *secinfo;
55a1ba9ba4Schristos /* Next entity in the hash table. */
56a1ba9ba4Schristos struct sec_merge_hash_entry *next;
57a1ba9ba4Schristos };
58a1ba9ba4Schristos
59a1ba9ba4Schristos /* The section merge hash table. */
60a1ba9ba4Schristos
61a1ba9ba4Schristos struct sec_merge_hash
62a1ba9ba4Schristos {
63a1ba9ba4Schristos struct bfd_hash_table table;
64a1ba9ba4Schristos /* Next available index. */
65a1ba9ba4Schristos bfd_size_type size;
66a1ba9ba4Schristos /* First entity in the SEC_MERGE sections of this type. */
67a1ba9ba4Schristos struct sec_merge_hash_entry *first;
68a1ba9ba4Schristos /* Last entity in the SEC_MERGE sections of this type. */
69a1ba9ba4Schristos struct sec_merge_hash_entry *last;
70a1ba9ba4Schristos /* Entity size. */
71a1ba9ba4Schristos unsigned int entsize;
72a1ba9ba4Schristos /* Are entries fixed size or zero terminated strings? */
73a1ba9ba4Schristos bfd_boolean strings;
74a1ba9ba4Schristos };
75a1ba9ba4Schristos
76a1ba9ba4Schristos struct sec_merge_info
77a1ba9ba4Schristos {
78a1ba9ba4Schristos /* Chain of sec_merge_infos. */
79a1ba9ba4Schristos struct sec_merge_info *next;
80a1ba9ba4Schristos /* Chain of sec_merge_sec_infos. */
81a1ba9ba4Schristos struct sec_merge_sec_info *chain;
82a1ba9ba4Schristos /* A hash table used to hold section content. */
83a1ba9ba4Schristos struct sec_merge_hash *htab;
84a1ba9ba4Schristos };
85a1ba9ba4Schristos
86a1ba9ba4Schristos struct sec_merge_sec_info
87a1ba9ba4Schristos {
88a1ba9ba4Schristos /* Chain of sec_merge_sec_infos. */
89a1ba9ba4Schristos struct sec_merge_sec_info *next;
90a1ba9ba4Schristos /* The corresponding section. */
91a1ba9ba4Schristos asection *sec;
92a1ba9ba4Schristos /* Pointer to merge_info pointing to us. */
93a1ba9ba4Schristos void **psecinfo;
94a1ba9ba4Schristos /* A hash table used to hold section content. */
95a1ba9ba4Schristos struct sec_merge_hash *htab;
96a1ba9ba4Schristos /* First string in this section. */
97a1ba9ba4Schristos struct sec_merge_hash_entry *first_str;
98a1ba9ba4Schristos /* Original section content. */
99a1ba9ba4Schristos unsigned char contents[1];
100a1ba9ba4Schristos };
101a1ba9ba4Schristos
102a1ba9ba4Schristos
103a1ba9ba4Schristos /* Routine to create an entry in a section merge hashtab. */
104a1ba9ba4Schristos
105a1ba9ba4Schristos static struct bfd_hash_entry *
sec_merge_hash_newfunc(struct bfd_hash_entry * entry,struct bfd_hash_table * table,const char * string)106a1ba9ba4Schristos sec_merge_hash_newfunc (struct bfd_hash_entry *entry,
107a1ba9ba4Schristos struct bfd_hash_table *table, const char *string)
108a1ba9ba4Schristos {
109a1ba9ba4Schristos /* Allocate the structure if it has not already been allocated by a
110a1ba9ba4Schristos subclass. */
111a1ba9ba4Schristos if (entry == NULL)
112a1ba9ba4Schristos entry = (struct bfd_hash_entry *)
113a1ba9ba4Schristos bfd_hash_allocate (table, sizeof (struct sec_merge_hash_entry));
114a1ba9ba4Schristos if (entry == NULL)
115a1ba9ba4Schristos return NULL;
116a1ba9ba4Schristos
117a1ba9ba4Schristos /* Call the allocation method of the superclass. */
118a1ba9ba4Schristos entry = bfd_hash_newfunc (entry, table, string);
119a1ba9ba4Schristos
120a1ba9ba4Schristos if (entry != NULL)
121a1ba9ba4Schristos {
122a1ba9ba4Schristos /* Initialize the local fields. */
123a1ba9ba4Schristos struct sec_merge_hash_entry *ret = (struct sec_merge_hash_entry *) entry;
124a1ba9ba4Schristos
125a1ba9ba4Schristos ret->u.suffix = NULL;
126a1ba9ba4Schristos ret->alignment = 0;
127a1ba9ba4Schristos ret->secinfo = NULL;
128a1ba9ba4Schristos ret->next = NULL;
129a1ba9ba4Schristos }
130a1ba9ba4Schristos
131a1ba9ba4Schristos return entry;
132a1ba9ba4Schristos }
133a1ba9ba4Schristos
134a1ba9ba4Schristos /* Look up an entry in a section merge hash table. */
135a1ba9ba4Schristos
136a1ba9ba4Schristos static struct sec_merge_hash_entry *
sec_merge_hash_lookup(struct sec_merge_hash * table,const char * string,unsigned int alignment,bfd_boolean create)137a1ba9ba4Schristos sec_merge_hash_lookup (struct sec_merge_hash *table, const char *string,
138a1ba9ba4Schristos unsigned int alignment, bfd_boolean create)
139a1ba9ba4Schristos {
140a1ba9ba4Schristos const unsigned char *s;
141a1ba9ba4Schristos unsigned long hash;
142a1ba9ba4Schristos unsigned int c;
143a1ba9ba4Schristos struct sec_merge_hash_entry *hashp;
144a1ba9ba4Schristos unsigned int len, i;
145a1ba9ba4Schristos unsigned int _index;
146a1ba9ba4Schristos
147a1ba9ba4Schristos hash = 0;
148a1ba9ba4Schristos len = 0;
149a1ba9ba4Schristos s = (const unsigned char *) string;
150a1ba9ba4Schristos if (table->strings)
151a1ba9ba4Schristos {
152a1ba9ba4Schristos if (table->entsize == 1)
153a1ba9ba4Schristos {
154a1ba9ba4Schristos while ((c = *s++) != '\0')
155a1ba9ba4Schristos {
156a1ba9ba4Schristos hash += c + (c << 17);
157a1ba9ba4Schristos hash ^= hash >> 2;
158a1ba9ba4Schristos ++len;
159a1ba9ba4Schristos }
160a1ba9ba4Schristos hash += len + (len << 17);
161a1ba9ba4Schristos }
162a1ba9ba4Schristos else
163a1ba9ba4Schristos {
164a1ba9ba4Schristos for (;;)
165a1ba9ba4Schristos {
166a1ba9ba4Schristos for (i = 0; i < table->entsize; ++i)
167a1ba9ba4Schristos if (s[i] != '\0')
168a1ba9ba4Schristos break;
169a1ba9ba4Schristos if (i == table->entsize)
170a1ba9ba4Schristos break;
171a1ba9ba4Schristos for (i = 0; i < table->entsize; ++i)
172a1ba9ba4Schristos {
173a1ba9ba4Schristos c = *s++;
174a1ba9ba4Schristos hash += c + (c << 17);
175a1ba9ba4Schristos hash ^= hash >> 2;
176a1ba9ba4Schristos }
177a1ba9ba4Schristos ++len;
178a1ba9ba4Schristos }
179a1ba9ba4Schristos hash += len + (len << 17);
180a1ba9ba4Schristos len *= table->entsize;
181a1ba9ba4Schristos }
182a1ba9ba4Schristos hash ^= hash >> 2;
183a1ba9ba4Schristos len += table->entsize;
184a1ba9ba4Schristos }
185a1ba9ba4Schristos else
186a1ba9ba4Schristos {
187a1ba9ba4Schristos for (i = 0; i < table->entsize; ++i)
188a1ba9ba4Schristos {
189a1ba9ba4Schristos c = *s++;
190a1ba9ba4Schristos hash += c + (c << 17);
191a1ba9ba4Schristos hash ^= hash >> 2;
192a1ba9ba4Schristos }
193a1ba9ba4Schristos len = table->entsize;
194a1ba9ba4Schristos }
195a1ba9ba4Schristos
196a1ba9ba4Schristos _index = hash % table->table.size;
197a1ba9ba4Schristos for (hashp = (struct sec_merge_hash_entry *) table->table.table[_index];
198a1ba9ba4Schristos hashp != NULL;
199a1ba9ba4Schristos hashp = (struct sec_merge_hash_entry *) hashp->root.next)
200a1ba9ba4Schristos {
201a1ba9ba4Schristos if (hashp->root.hash == hash
202a1ba9ba4Schristos && len == hashp->len
203a1ba9ba4Schristos && memcmp (hashp->root.string, string, len) == 0)
204a1ba9ba4Schristos {
205a1ba9ba4Schristos /* If the string we found does not have at least the required
206a1ba9ba4Schristos alignment, we need to insert another copy. */
207a1ba9ba4Schristos if (hashp->alignment < alignment)
208a1ba9ba4Schristos {
209a1ba9ba4Schristos if (create)
210a1ba9ba4Schristos {
211a1ba9ba4Schristos /* Mark the less aligned copy as deleted. */
212a1ba9ba4Schristos hashp->len = 0;
213a1ba9ba4Schristos hashp->alignment = 0;
214a1ba9ba4Schristos }
215a1ba9ba4Schristos break;
216a1ba9ba4Schristos }
217a1ba9ba4Schristos return hashp;
218a1ba9ba4Schristos }
219a1ba9ba4Schristos }
220a1ba9ba4Schristos
221a1ba9ba4Schristos if (! create)
222a1ba9ba4Schristos return NULL;
223a1ba9ba4Schristos
224a1ba9ba4Schristos hashp = ((struct sec_merge_hash_entry *)
225a1ba9ba4Schristos bfd_hash_insert (&table->table, string, hash));
226a1ba9ba4Schristos if (hashp == NULL)
227a1ba9ba4Schristos return NULL;
228a1ba9ba4Schristos hashp->len = len;
229a1ba9ba4Schristos hashp->alignment = alignment;
230a1ba9ba4Schristos return hashp;
231a1ba9ba4Schristos }
232a1ba9ba4Schristos
233a1ba9ba4Schristos /* Create a new hash table. */
234a1ba9ba4Schristos
235a1ba9ba4Schristos static struct sec_merge_hash *
sec_merge_init(unsigned int entsize,bfd_boolean strings)236a1ba9ba4Schristos sec_merge_init (unsigned int entsize, bfd_boolean strings)
237a1ba9ba4Schristos {
238a1ba9ba4Schristos struct sec_merge_hash *table;
239a1ba9ba4Schristos
240a1ba9ba4Schristos table = (struct sec_merge_hash *) bfd_malloc (sizeof (struct sec_merge_hash));
241a1ba9ba4Schristos if (table == NULL)
242a1ba9ba4Schristos return NULL;
243a1ba9ba4Schristos
244a1ba9ba4Schristos if (! bfd_hash_table_init_n (&table->table, sec_merge_hash_newfunc,
245a1ba9ba4Schristos sizeof (struct sec_merge_hash_entry), 16699))
246a1ba9ba4Schristos {
247a1ba9ba4Schristos free (table);
248a1ba9ba4Schristos return NULL;
249a1ba9ba4Schristos }
250a1ba9ba4Schristos
251a1ba9ba4Schristos table->size = 0;
252a1ba9ba4Schristos table->first = NULL;
253a1ba9ba4Schristos table->last = NULL;
254a1ba9ba4Schristos table->entsize = entsize;
255a1ba9ba4Schristos table->strings = strings;
256a1ba9ba4Schristos
257a1ba9ba4Schristos return table;
258a1ba9ba4Schristos }
259a1ba9ba4Schristos
260a1ba9ba4Schristos /* Get the index of an entity in a hash table, adding it if it is not
261a1ba9ba4Schristos already present. */
262a1ba9ba4Schristos
263a1ba9ba4Schristos static struct sec_merge_hash_entry *
sec_merge_add(struct sec_merge_hash * tab,const char * str,unsigned int alignment,struct sec_merge_sec_info * secinfo)264a1ba9ba4Schristos sec_merge_add (struct sec_merge_hash *tab, const char *str,
265a1ba9ba4Schristos unsigned int alignment, struct sec_merge_sec_info *secinfo)
266a1ba9ba4Schristos {
267a1ba9ba4Schristos struct sec_merge_hash_entry *entry;
268a1ba9ba4Schristos
269a1ba9ba4Schristos entry = sec_merge_hash_lookup (tab, str, alignment, TRUE);
270a1ba9ba4Schristos if (entry == NULL)
271a1ba9ba4Schristos return NULL;
272a1ba9ba4Schristos
273a1ba9ba4Schristos if (entry->secinfo == NULL)
274a1ba9ba4Schristos {
275a1ba9ba4Schristos tab->size++;
276a1ba9ba4Schristos entry->secinfo = secinfo;
277a1ba9ba4Schristos if (tab->first == NULL)
278a1ba9ba4Schristos tab->first = entry;
279a1ba9ba4Schristos else
280a1ba9ba4Schristos tab->last->next = entry;
281a1ba9ba4Schristos tab->last = entry;
282a1ba9ba4Schristos }
283a1ba9ba4Schristos
284a1ba9ba4Schristos return entry;
285a1ba9ba4Schristos }
286a1ba9ba4Schristos
287a1ba9ba4Schristos static bfd_boolean
sec_merge_emit(bfd * abfd,struct sec_merge_hash_entry * entry,unsigned char * contents,file_ptr offset)288a1ba9ba4Schristos sec_merge_emit (bfd *abfd, struct sec_merge_hash_entry *entry,
289a1ba9ba4Schristos unsigned char *contents, file_ptr offset)
290a1ba9ba4Schristos {
291a1ba9ba4Schristos struct sec_merge_sec_info *secinfo = entry->secinfo;
292a1ba9ba4Schristos asection *sec = secinfo->sec;
293a1ba9ba4Schristos char *pad = NULL;
294a1ba9ba4Schristos bfd_size_type off = 0;
295*184b2d41Schristos unsigned int opb = bfd_octets_per_byte (abfd, sec);
296*184b2d41Schristos int alignment_power = sec->output_section->alignment_power * opb;
297*184b2d41Schristos bfd_size_type pad_len; /* Octets. */
298a1ba9ba4Schristos
299051580eeSchristos /* FIXME: If alignment_power is 0 then really we should scan the
300051580eeSchristos entry list for the largest required alignment and use that. */
301051580eeSchristos pad_len = alignment_power ? ((bfd_size_type) 1 << alignment_power) : 16;
302051580eeSchristos
303051580eeSchristos pad = (char *) bfd_zmalloc (pad_len);
304a1ba9ba4Schristos if (pad == NULL)
305a1ba9ba4Schristos return FALSE;
306a1ba9ba4Schristos
307a1ba9ba4Schristos for (; entry != NULL && entry->secinfo == secinfo; entry = entry->next)
308a1ba9ba4Schristos {
309a1ba9ba4Schristos const char *str;
310a1ba9ba4Schristos bfd_size_type len;
311a1ba9ba4Schristos
312a1ba9ba4Schristos len = -off & (entry->alignment - 1);
313a1ba9ba4Schristos if (len != 0)
314a1ba9ba4Schristos {
315051580eeSchristos BFD_ASSERT (len <= pad_len);
316a1ba9ba4Schristos if (contents)
317a1ba9ba4Schristos {
318a1ba9ba4Schristos memcpy (contents + offset, pad, len);
319a1ba9ba4Schristos offset += len;
320a1ba9ba4Schristos }
321a1ba9ba4Schristos else if (bfd_bwrite (pad, len, abfd) != len)
322a1ba9ba4Schristos goto err;
323a1ba9ba4Schristos off += len;
324a1ba9ba4Schristos }
325a1ba9ba4Schristos
326a1ba9ba4Schristos str = entry->root.string;
327a1ba9ba4Schristos len = entry->len;
328a1ba9ba4Schristos
329a1ba9ba4Schristos if (contents)
330a1ba9ba4Schristos {
331a1ba9ba4Schristos memcpy (contents + offset, str, len);
332a1ba9ba4Schristos offset += len;
333a1ba9ba4Schristos }
334a1ba9ba4Schristos else if (bfd_bwrite (str, len, abfd) != len)
335a1ba9ba4Schristos goto err;
336a1ba9ba4Schristos
337a1ba9ba4Schristos off += len;
338a1ba9ba4Schristos }
339a1ba9ba4Schristos
340a1ba9ba4Schristos /* Trailing alignment needed? */
341a1ba9ba4Schristos off = sec->size - off;
342a1ba9ba4Schristos if (pad != NULL && off != 0)
343a1ba9ba4Schristos {
344051580eeSchristos BFD_ASSERT (off <= pad_len);
345a1ba9ba4Schristos if (contents)
346a1ba9ba4Schristos memcpy (contents + offset, pad, off);
347a1ba9ba4Schristos else if (bfd_bwrite (pad, off, abfd) != off)
348a1ba9ba4Schristos goto err;
349a1ba9ba4Schristos }
350a1ba9ba4Schristos
351a1ba9ba4Schristos free (pad);
352a1ba9ba4Schristos return TRUE;
353a1ba9ba4Schristos
354a1ba9ba4Schristos err:
355a1ba9ba4Schristos free (pad);
356a1ba9ba4Schristos return FALSE;
357a1ba9ba4Schristos }
358a1ba9ba4Schristos
359a1ba9ba4Schristos /* Register a SEC_MERGE section as a candidate for merging.
360a1ba9ba4Schristos This function is called for all non-dynamic SEC_MERGE input sections. */
361a1ba9ba4Schristos
362a1ba9ba4Schristos bfd_boolean
_bfd_add_merge_section(bfd * abfd,void ** psinfo,asection * sec,void ** psecinfo)363a1ba9ba4Schristos _bfd_add_merge_section (bfd *abfd, void **psinfo, asection *sec,
364a1ba9ba4Schristos void **psecinfo)
365a1ba9ba4Schristos {
366a1ba9ba4Schristos struct sec_merge_info *sinfo;
367a1ba9ba4Schristos struct sec_merge_sec_info *secinfo;
368*184b2d41Schristos unsigned int alignment_power; /* Octets. */
369*184b2d41Schristos unsigned int align; /* Octets. */
370a1ba9ba4Schristos bfd_size_type amt;
371a1ba9ba4Schristos bfd_byte *contents;
372*184b2d41Schristos unsigned int opb = bfd_octets_per_byte (abfd, sec);
373a1ba9ba4Schristos
374a1ba9ba4Schristos if ((abfd->flags & DYNAMIC) != 0
375a1ba9ba4Schristos || (sec->flags & SEC_MERGE) == 0)
376a1ba9ba4Schristos abort ();
377a1ba9ba4Schristos
378a1ba9ba4Schristos if (sec->size == 0
379a1ba9ba4Schristos || (sec->flags & SEC_EXCLUDE) != 0
380a1ba9ba4Schristos || sec->entsize == 0)
381a1ba9ba4Schristos return TRUE;
382a1ba9ba4Schristos
383051580eeSchristos if (sec->size % sec->entsize != 0)
384051580eeSchristos return TRUE;
385051580eeSchristos
386a1ba9ba4Schristos if ((sec->flags & SEC_RELOC) != 0)
387a1ba9ba4Schristos {
388a1ba9ba4Schristos /* We aren't prepared to handle relocations in merged sections. */
389a1ba9ba4Schristos return TRUE;
390a1ba9ba4Schristos }
391a1ba9ba4Schristos
392051580eeSchristos #ifndef CHAR_BIT
393051580eeSchristos #define CHAR_BIT 8
394051580eeSchristos #endif
395*184b2d41Schristos alignment_power = sec->alignment_power * opb;
396*184b2d41Schristos if (alignment_power >= sizeof (align) * CHAR_BIT)
397051580eeSchristos return TRUE;
398051580eeSchristos
399*184b2d41Schristos align = 1u << alignment_power;
400051580eeSchristos if ((sec->entsize < align
401a1ba9ba4Schristos && ((sec->entsize & (sec->entsize - 1))
402a1ba9ba4Schristos || !(sec->flags & SEC_STRINGS)))
403051580eeSchristos || (sec->entsize > align
404051580eeSchristos && (sec->entsize & (align - 1))))
405a1ba9ba4Schristos {
406a1ba9ba4Schristos /* Sanity check. If string character size is smaller than
407a1ba9ba4Schristos alignment, then we require character size to be a power
408a1ba9ba4Schristos of 2, otherwise character size must be integer multiple
409a1ba9ba4Schristos of alignment. For non-string constants, alignment must
410a1ba9ba4Schristos be smaller than or equal to entity size and entity size
411a1ba9ba4Schristos must be integer multiple of alignment. */
412a1ba9ba4Schristos return TRUE;
413a1ba9ba4Schristos }
414a1ba9ba4Schristos
415a1ba9ba4Schristos for (sinfo = (struct sec_merge_info *) *psinfo; sinfo; sinfo = sinfo->next)
416a1ba9ba4Schristos if ((secinfo = sinfo->chain)
417a1ba9ba4Schristos && ! ((secinfo->sec->flags ^ sec->flags) & (SEC_MERGE | SEC_STRINGS))
418a1ba9ba4Schristos && secinfo->sec->entsize == sec->entsize
419a1ba9ba4Schristos && secinfo->sec->alignment_power == sec->alignment_power
420a1ba9ba4Schristos && secinfo->sec->output_section == sec->output_section)
421a1ba9ba4Schristos break;
422a1ba9ba4Schristos
423a1ba9ba4Schristos if (sinfo == NULL)
424a1ba9ba4Schristos {
425a1ba9ba4Schristos /* Initialize the information we need to keep track of. */
426a1ba9ba4Schristos sinfo = (struct sec_merge_info *)
427a1ba9ba4Schristos bfd_alloc (abfd, sizeof (struct sec_merge_info));
428a1ba9ba4Schristos if (sinfo == NULL)
429a1ba9ba4Schristos goto error_return;
430a1ba9ba4Schristos sinfo->next = (struct sec_merge_info *) *psinfo;
431a1ba9ba4Schristos sinfo->chain = NULL;
432a1ba9ba4Schristos *psinfo = sinfo;
433a1ba9ba4Schristos sinfo->htab = sec_merge_init (sec->entsize, (sec->flags & SEC_STRINGS));
434a1ba9ba4Schristos if (sinfo->htab == NULL)
435a1ba9ba4Schristos goto error_return;
436a1ba9ba4Schristos }
437a1ba9ba4Schristos
438a1ba9ba4Schristos /* Read the section from abfd. */
439a1ba9ba4Schristos
440a1ba9ba4Schristos amt = sizeof (struct sec_merge_sec_info) - 1 + sec->size;
441a1ba9ba4Schristos if (sec->flags & SEC_STRINGS)
442a1ba9ba4Schristos /* Some versions of gcc may emit a string without a zero terminator.
443a1ba9ba4Schristos See http://gcc.gnu.org/ml/gcc-patches/2006-06/msg01004.html
444a1ba9ba4Schristos Allocate space for an extra zero. */
445a1ba9ba4Schristos amt += sec->entsize;
446a1ba9ba4Schristos *psecinfo = bfd_alloc (abfd, amt);
447a1ba9ba4Schristos if (*psecinfo == NULL)
448a1ba9ba4Schristos goto error_return;
449a1ba9ba4Schristos
450a1ba9ba4Schristos secinfo = (struct sec_merge_sec_info *) *psecinfo;
451a1ba9ba4Schristos if (sinfo->chain)
452a1ba9ba4Schristos {
453a1ba9ba4Schristos secinfo->next = sinfo->chain->next;
454a1ba9ba4Schristos sinfo->chain->next = secinfo;
455a1ba9ba4Schristos }
456a1ba9ba4Schristos else
457a1ba9ba4Schristos secinfo->next = secinfo;
458a1ba9ba4Schristos sinfo->chain = secinfo;
459a1ba9ba4Schristos secinfo->sec = sec;
460a1ba9ba4Schristos secinfo->psecinfo = psecinfo;
461a1ba9ba4Schristos secinfo->htab = sinfo->htab;
462a1ba9ba4Schristos secinfo->first_str = NULL;
463a1ba9ba4Schristos
464a1ba9ba4Schristos sec->rawsize = sec->size;
465a1ba9ba4Schristos if (sec->flags & SEC_STRINGS)
466a1ba9ba4Schristos memset (secinfo->contents + sec->size, 0, sec->entsize);
467a1ba9ba4Schristos contents = secinfo->contents;
468a1ba9ba4Schristos if (! bfd_get_full_section_contents (sec->owner, sec, &contents))
469a1ba9ba4Schristos goto error_return;
470a1ba9ba4Schristos
471a1ba9ba4Schristos return TRUE;
472a1ba9ba4Schristos
473a1ba9ba4Schristos error_return:
474a1ba9ba4Schristos *psecinfo = NULL;
475a1ba9ba4Schristos return FALSE;
476a1ba9ba4Schristos }
477a1ba9ba4Schristos
478a1ba9ba4Schristos /* Record one section into the hash table. */
479a1ba9ba4Schristos static bfd_boolean
record_section(struct sec_merge_info * sinfo,struct sec_merge_sec_info * secinfo)480a1ba9ba4Schristos record_section (struct sec_merge_info *sinfo,
481a1ba9ba4Schristos struct sec_merge_sec_info *secinfo)
482a1ba9ba4Schristos {
483a1ba9ba4Schristos asection *sec = secinfo->sec;
484a1ba9ba4Schristos struct sec_merge_hash_entry *entry;
485a1ba9ba4Schristos bfd_boolean nul;
486a1ba9ba4Schristos unsigned char *p, *end;
487a1ba9ba4Schristos bfd_vma mask, eltalign;
488a1ba9ba4Schristos unsigned int align, i;
489a1ba9ba4Schristos
490a1ba9ba4Schristos align = sec->alignment_power;
491a1ba9ba4Schristos end = secinfo->contents + sec->size;
492a1ba9ba4Schristos nul = FALSE;
493a1ba9ba4Schristos mask = ((bfd_vma) 1 << align) - 1;
494a1ba9ba4Schristos if (sec->flags & SEC_STRINGS)
495a1ba9ba4Schristos {
496a1ba9ba4Schristos for (p = secinfo->contents; p < end; )
497a1ba9ba4Schristos {
498a1ba9ba4Schristos eltalign = p - secinfo->contents;
499a1ba9ba4Schristos eltalign = ((eltalign ^ (eltalign - 1)) + 1) >> 1;
500a1ba9ba4Schristos if (!eltalign || eltalign > mask)
501a1ba9ba4Schristos eltalign = mask + 1;
502a1ba9ba4Schristos entry = sec_merge_add (sinfo->htab, (char *) p, (unsigned) eltalign,
503a1ba9ba4Schristos secinfo);
504a1ba9ba4Schristos if (! entry)
505a1ba9ba4Schristos goto error_return;
506a1ba9ba4Schristos p += entry->len;
507a1ba9ba4Schristos if (sec->entsize == 1)
508a1ba9ba4Schristos {
509a1ba9ba4Schristos while (p < end && *p == 0)
510a1ba9ba4Schristos {
511a1ba9ba4Schristos if (!nul && !((p - secinfo->contents) & mask))
512a1ba9ba4Schristos {
513a1ba9ba4Schristos nul = TRUE;
514a1ba9ba4Schristos entry = sec_merge_add (sinfo->htab, "",
515a1ba9ba4Schristos (unsigned) mask + 1, secinfo);
516a1ba9ba4Schristos if (! entry)
517a1ba9ba4Schristos goto error_return;
518a1ba9ba4Schristos }
519a1ba9ba4Schristos p++;
520a1ba9ba4Schristos }
521a1ba9ba4Schristos }
522a1ba9ba4Schristos else
523a1ba9ba4Schristos {
524a1ba9ba4Schristos while (p < end)
525a1ba9ba4Schristos {
526a1ba9ba4Schristos for (i = 0; i < sec->entsize; i++)
527a1ba9ba4Schristos if (p[i] != '\0')
528a1ba9ba4Schristos break;
529a1ba9ba4Schristos if (i != sec->entsize)
530a1ba9ba4Schristos break;
531a1ba9ba4Schristos if (!nul && !((p - secinfo->contents) & mask))
532a1ba9ba4Schristos {
533a1ba9ba4Schristos nul = TRUE;
534a1ba9ba4Schristos entry = sec_merge_add (sinfo->htab, (char *) p,
535a1ba9ba4Schristos (unsigned) mask + 1, secinfo);
536a1ba9ba4Schristos if (! entry)
537a1ba9ba4Schristos goto error_return;
538a1ba9ba4Schristos }
539a1ba9ba4Schristos p += sec->entsize;
540a1ba9ba4Schristos }
541a1ba9ba4Schristos }
542a1ba9ba4Schristos }
543a1ba9ba4Schristos }
544a1ba9ba4Schristos else
545a1ba9ba4Schristos {
546a1ba9ba4Schristos for (p = secinfo->contents; p < end; p += sec->entsize)
547a1ba9ba4Schristos {
548a1ba9ba4Schristos entry = sec_merge_add (sinfo->htab, (char *) p, 1, secinfo);
549a1ba9ba4Schristos if (! entry)
550a1ba9ba4Schristos goto error_return;
551a1ba9ba4Schristos }
552a1ba9ba4Schristos }
553a1ba9ba4Schristos
554a1ba9ba4Schristos return TRUE;
555a1ba9ba4Schristos
556a1ba9ba4Schristos error_return:
557a1ba9ba4Schristos for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
558a1ba9ba4Schristos *secinfo->psecinfo = NULL;
559a1ba9ba4Schristos return FALSE;
560a1ba9ba4Schristos }
561a1ba9ba4Schristos
562*184b2d41Schristos /* qsort comparison function. Won't ever return zero as all entries
563*184b2d41Schristos differ, so there is no issue with qsort stability here. */
564*184b2d41Schristos
565a1ba9ba4Schristos static int
strrevcmp(const void * a,const void * b)566a1ba9ba4Schristos strrevcmp (const void *a, const void *b)
567a1ba9ba4Schristos {
568a1ba9ba4Schristos struct sec_merge_hash_entry *A = *(struct sec_merge_hash_entry **) a;
569a1ba9ba4Schristos struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b;
570a1ba9ba4Schristos unsigned int lenA = A->len;
571a1ba9ba4Schristos unsigned int lenB = B->len;
572a1ba9ba4Schristos const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
573a1ba9ba4Schristos const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
574a1ba9ba4Schristos int l = lenA < lenB ? lenA : lenB;
575a1ba9ba4Schristos
576a1ba9ba4Schristos while (l)
577a1ba9ba4Schristos {
578a1ba9ba4Schristos if (*s != *t)
579a1ba9ba4Schristos return (int) *s - (int) *t;
580a1ba9ba4Schristos s--;
581a1ba9ba4Schristos t--;
582a1ba9ba4Schristos l--;
583a1ba9ba4Schristos }
584a1ba9ba4Schristos return lenA - lenB;
585a1ba9ba4Schristos }
586a1ba9ba4Schristos
587a1ba9ba4Schristos /* Like strrevcmp, but for the case where all strings have the same
588a1ba9ba4Schristos alignment > entsize. */
589a1ba9ba4Schristos
590a1ba9ba4Schristos static int
strrevcmp_align(const void * a,const void * b)591a1ba9ba4Schristos strrevcmp_align (const void *a, const void *b)
592a1ba9ba4Schristos {
593a1ba9ba4Schristos struct sec_merge_hash_entry *A = *(struct sec_merge_hash_entry **) a;
594a1ba9ba4Schristos struct sec_merge_hash_entry *B = *(struct sec_merge_hash_entry **) b;
595a1ba9ba4Schristos unsigned int lenA = A->len;
596a1ba9ba4Schristos unsigned int lenB = B->len;
597a1ba9ba4Schristos const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
598a1ba9ba4Schristos const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
599a1ba9ba4Schristos int l = lenA < lenB ? lenA : lenB;
600a1ba9ba4Schristos int tail_align = (lenA & (A->alignment - 1)) - (lenB & (A->alignment - 1));
601a1ba9ba4Schristos
602a1ba9ba4Schristos if (tail_align != 0)
603a1ba9ba4Schristos return tail_align;
604a1ba9ba4Schristos
605a1ba9ba4Schristos while (l)
606a1ba9ba4Schristos {
607a1ba9ba4Schristos if (*s != *t)
608a1ba9ba4Schristos return (int) *s - (int) *t;
609a1ba9ba4Schristos s--;
610a1ba9ba4Schristos t--;
611a1ba9ba4Schristos l--;
612a1ba9ba4Schristos }
613a1ba9ba4Schristos return lenA - lenB;
614a1ba9ba4Schristos }
615a1ba9ba4Schristos
616a1ba9ba4Schristos static inline int
is_suffix(const struct sec_merge_hash_entry * A,const struct sec_merge_hash_entry * B)617a1ba9ba4Schristos is_suffix (const struct sec_merge_hash_entry *A,
618a1ba9ba4Schristos const struct sec_merge_hash_entry *B)
619a1ba9ba4Schristos {
620a1ba9ba4Schristos if (A->len <= B->len)
621a1ba9ba4Schristos /* B cannot be a suffix of A unless A is equal to B, which is guaranteed
622a1ba9ba4Schristos not to be equal by the hash table. */
623a1ba9ba4Schristos return 0;
624a1ba9ba4Schristos
625a1ba9ba4Schristos return memcmp (A->root.string + (A->len - B->len),
626a1ba9ba4Schristos B->root.string, B->len) == 0;
627a1ba9ba4Schristos }
628a1ba9ba4Schristos
629a1ba9ba4Schristos /* This is a helper function for _bfd_merge_sections. It attempts to
630a1ba9ba4Schristos merge strings matching suffixes of longer strings. */
631*184b2d41Schristos static struct sec_merge_sec_info *
merge_strings(struct sec_merge_info * sinfo)632a1ba9ba4Schristos merge_strings (struct sec_merge_info *sinfo)
633a1ba9ba4Schristos {
634a1ba9ba4Schristos struct sec_merge_hash_entry **array, **a, *e;
635a1ba9ba4Schristos struct sec_merge_sec_info *secinfo;
636a1ba9ba4Schristos bfd_size_type size, amt;
637a1ba9ba4Schristos unsigned int alignment = 0;
638a1ba9ba4Schristos
639a1ba9ba4Schristos /* Now sort the strings */
640a1ba9ba4Schristos amt = sinfo->htab->size * sizeof (struct sec_merge_hash_entry *);
641a1ba9ba4Schristos array = (struct sec_merge_hash_entry **) bfd_malloc (amt);
642a1ba9ba4Schristos if (array == NULL)
643*184b2d41Schristos return NULL;
644a1ba9ba4Schristos
645a1ba9ba4Schristos for (e = sinfo->htab->first, a = array; e; e = e->next)
646a1ba9ba4Schristos if (e->alignment)
647a1ba9ba4Schristos {
648a1ba9ba4Schristos *a++ = e;
649a1ba9ba4Schristos /* Adjust the length to not include the zero terminator. */
650a1ba9ba4Schristos e->len -= sinfo->htab->entsize;
651a1ba9ba4Schristos if (alignment != e->alignment)
652a1ba9ba4Schristos {
653a1ba9ba4Schristos if (alignment == 0)
654a1ba9ba4Schristos alignment = e->alignment;
655a1ba9ba4Schristos else
656a1ba9ba4Schristos alignment = (unsigned) -1;
657a1ba9ba4Schristos }
658a1ba9ba4Schristos }
659a1ba9ba4Schristos
660a1ba9ba4Schristos sinfo->htab->size = a - array;
661a1ba9ba4Schristos if (sinfo->htab->size != 0)
662a1ba9ba4Schristos {
663a1ba9ba4Schristos qsort (array, (size_t) sinfo->htab->size,
664a1ba9ba4Schristos sizeof (struct sec_merge_hash_entry *),
665a1ba9ba4Schristos (alignment != (unsigned) -1 && alignment > sinfo->htab->entsize
666a1ba9ba4Schristos ? strrevcmp_align : strrevcmp));
667a1ba9ba4Schristos
668a1ba9ba4Schristos /* Loop over the sorted array and merge suffixes */
669a1ba9ba4Schristos e = *--a;
670a1ba9ba4Schristos e->len += sinfo->htab->entsize;
671a1ba9ba4Schristos while (--a >= array)
672a1ba9ba4Schristos {
673a1ba9ba4Schristos struct sec_merge_hash_entry *cmp = *a;
674a1ba9ba4Schristos
675a1ba9ba4Schristos cmp->len += sinfo->htab->entsize;
676a1ba9ba4Schristos if (e->alignment >= cmp->alignment
677a1ba9ba4Schristos && !((e->len - cmp->len) & (cmp->alignment - 1))
678a1ba9ba4Schristos && is_suffix (e, cmp))
679a1ba9ba4Schristos {
680a1ba9ba4Schristos cmp->u.suffix = e;
681a1ba9ba4Schristos cmp->alignment = 0;
682a1ba9ba4Schristos }
683a1ba9ba4Schristos else
684a1ba9ba4Schristos e = cmp;
685a1ba9ba4Schristos }
686a1ba9ba4Schristos }
687a1ba9ba4Schristos
688a1ba9ba4Schristos free (array);
689a1ba9ba4Schristos
690a1ba9ba4Schristos /* Now assign positions to the strings we want to keep. */
691a1ba9ba4Schristos size = 0;
692a1ba9ba4Schristos secinfo = sinfo->htab->first->secinfo;
693a1ba9ba4Schristos for (e = sinfo->htab->first; e; e = e->next)
694a1ba9ba4Schristos {
695a1ba9ba4Schristos if (e->secinfo != secinfo)
696a1ba9ba4Schristos {
697a1ba9ba4Schristos secinfo->sec->size = size;
698a1ba9ba4Schristos secinfo = e->secinfo;
699a1ba9ba4Schristos }
700a1ba9ba4Schristos if (e->alignment)
701a1ba9ba4Schristos {
702a1ba9ba4Schristos if (e->secinfo->first_str == NULL)
703a1ba9ba4Schristos {
704a1ba9ba4Schristos e->secinfo->first_str = e;
705a1ba9ba4Schristos size = 0;
706a1ba9ba4Schristos }
707a1ba9ba4Schristos size = (size + e->alignment - 1) & ~((bfd_vma) e->alignment - 1);
708a1ba9ba4Schristos e->u.index = size;
709a1ba9ba4Schristos size += e->len;
710a1ba9ba4Schristos }
711a1ba9ba4Schristos }
712a1ba9ba4Schristos secinfo->sec->size = size;
713a1ba9ba4Schristos
714a1ba9ba4Schristos /* And now adjust the rest, removing them from the chain (but not hashtable)
715a1ba9ba4Schristos at the same time. */
716a1ba9ba4Schristos for (a = &sinfo->htab->first, e = *a; e; e = e->next)
717a1ba9ba4Schristos if (e->alignment)
718a1ba9ba4Schristos a = &e->next;
719a1ba9ba4Schristos else
720a1ba9ba4Schristos {
721a1ba9ba4Schristos *a = e->next;
722a1ba9ba4Schristos if (e->len)
723a1ba9ba4Schristos {
724a1ba9ba4Schristos e->secinfo = e->u.suffix->secinfo;
725a1ba9ba4Schristos e->alignment = e->u.suffix->alignment;
726a1ba9ba4Schristos e->u.index = e->u.suffix->u.index + (e->u.suffix->len - e->len);
727a1ba9ba4Schristos }
728a1ba9ba4Schristos }
729*184b2d41Schristos return secinfo;
730a1ba9ba4Schristos }
731a1ba9ba4Schristos
732a1ba9ba4Schristos /* This function is called once after all SEC_MERGE sections are registered
733a1ba9ba4Schristos with _bfd_merge_section. */
734a1ba9ba4Schristos
735a1ba9ba4Schristos bfd_boolean
_bfd_merge_sections(bfd * abfd,struct bfd_link_info * info ATTRIBUTE_UNUSED,void * xsinfo,void (* remove_hook)(bfd *,asection *))736a1ba9ba4Schristos _bfd_merge_sections (bfd *abfd,
737a1ba9ba4Schristos struct bfd_link_info *info ATTRIBUTE_UNUSED,
738a1ba9ba4Schristos void *xsinfo,
739a1ba9ba4Schristos void (*remove_hook) (bfd *, asection *))
740a1ba9ba4Schristos {
741a1ba9ba4Schristos struct sec_merge_info *sinfo;
742a1ba9ba4Schristos
743a1ba9ba4Schristos for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next)
744a1ba9ba4Schristos {
745a1ba9ba4Schristos struct sec_merge_sec_info *secinfo;
746*184b2d41Schristos bfd_size_type align; /* Bytes. */
747a1ba9ba4Schristos
748a1ba9ba4Schristos if (! sinfo->chain)
749a1ba9ba4Schristos continue;
750a1ba9ba4Schristos
751a1ba9ba4Schristos /* Move sinfo->chain to head of the chain, terminate it. */
752a1ba9ba4Schristos secinfo = sinfo->chain;
753a1ba9ba4Schristos sinfo->chain = secinfo->next;
754a1ba9ba4Schristos secinfo->next = NULL;
755a1ba9ba4Schristos
756a1ba9ba4Schristos /* Record the sections into the hash table. */
757*184b2d41Schristos align = 1;
758a1ba9ba4Schristos for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
759a1ba9ba4Schristos if (secinfo->sec->flags & SEC_EXCLUDE)
760a1ba9ba4Schristos {
761a1ba9ba4Schristos *secinfo->psecinfo = NULL;
762a1ba9ba4Schristos if (remove_hook)
763a1ba9ba4Schristos (*remove_hook) (abfd, secinfo->sec);
764a1ba9ba4Schristos }
765*184b2d41Schristos else
766*184b2d41Schristos {
767*184b2d41Schristos if (!record_section (sinfo, secinfo))
768051580eeSchristos return FALSE;
769*184b2d41Schristos if (align)
770*184b2d41Schristos {
771*184b2d41Schristos unsigned int opb = bfd_octets_per_byte (abfd, secinfo->sec);
772a1ba9ba4Schristos
773*184b2d41Schristos align = (bfd_size_type) 1 << secinfo->sec->alignment_power;
774*184b2d41Schristos if (((secinfo->sec->size / opb) & (align - 1)) != 0)
775*184b2d41Schristos align = 0;
776*184b2d41Schristos }
777*184b2d41Schristos }
778a1ba9ba4Schristos
779a1ba9ba4Schristos if (sinfo->htab->first == NULL)
780a1ba9ba4Schristos continue;
781a1ba9ba4Schristos
782a1ba9ba4Schristos if (sinfo->htab->strings)
783051580eeSchristos {
784*184b2d41Schristos secinfo = merge_strings (sinfo);
785*184b2d41Schristos if (!secinfo)
786051580eeSchristos return FALSE;
787051580eeSchristos }
788a1ba9ba4Schristos else
789a1ba9ba4Schristos {
790a1ba9ba4Schristos struct sec_merge_hash_entry *e;
791*184b2d41Schristos bfd_size_type size = 0; /* Octets. */
792a1ba9ba4Schristos
793a1ba9ba4Schristos /* Things are much simpler for non-strings.
794a1ba9ba4Schristos Just assign them slots in the section. */
795a1ba9ba4Schristos secinfo = NULL;
796a1ba9ba4Schristos for (e = sinfo->htab->first; e; e = e->next)
797a1ba9ba4Schristos {
798a1ba9ba4Schristos if (e->secinfo->first_str == NULL)
799a1ba9ba4Schristos {
800a1ba9ba4Schristos if (secinfo)
801a1ba9ba4Schristos secinfo->sec->size = size;
802a1ba9ba4Schristos e->secinfo->first_str = e;
803a1ba9ba4Schristos size = 0;
804a1ba9ba4Schristos }
805*184b2d41Schristos size = (size + e->alignment - 1) & ~((bfd_vma) e->alignment - 1);
806a1ba9ba4Schristos e->u.index = size;
807a1ba9ba4Schristos size += e->len;
808a1ba9ba4Schristos secinfo = e->secinfo;
809a1ba9ba4Schristos }
810a1ba9ba4Schristos secinfo->sec->size = size;
811a1ba9ba4Schristos }
812a1ba9ba4Schristos
813*184b2d41Schristos /* If the input sections were padded according to their alignments,
814*184b2d41Schristos then pad the output too. */
815*184b2d41Schristos if (align)
816*184b2d41Schristos secinfo->sec->size = (secinfo->sec->size + align - 1) & -align;
817*184b2d41Schristos
818a1ba9ba4Schristos /* Finally remove all input sections which have not made it into
819a1ba9ba4Schristos the hash table at all. */
820a1ba9ba4Schristos for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next)
821a1ba9ba4Schristos if (secinfo->first_str == NULL)
822a1ba9ba4Schristos secinfo->sec->flags |= SEC_EXCLUDE | SEC_KEEP;
823a1ba9ba4Schristos }
824a1ba9ba4Schristos
825a1ba9ba4Schristos return TRUE;
826a1ba9ba4Schristos }
827a1ba9ba4Schristos
828a1ba9ba4Schristos /* Write out the merged section. */
829a1ba9ba4Schristos
830a1ba9ba4Schristos bfd_boolean
_bfd_write_merged_section(bfd * output_bfd,asection * sec,void * psecinfo)831a1ba9ba4Schristos _bfd_write_merged_section (bfd *output_bfd, asection *sec, void *psecinfo)
832a1ba9ba4Schristos {
833a1ba9ba4Schristos struct sec_merge_sec_info *secinfo;
834a1ba9ba4Schristos file_ptr pos;
835a1ba9ba4Schristos unsigned char *contents;
836a1ba9ba4Schristos Elf_Internal_Shdr *hdr;
837a1ba9ba4Schristos
838a1ba9ba4Schristos secinfo = (struct sec_merge_sec_info *) psecinfo;
839a1ba9ba4Schristos
840a1ba9ba4Schristos if (!secinfo)
841a1ba9ba4Schristos return FALSE;
842a1ba9ba4Schristos
843a1ba9ba4Schristos if (secinfo->first_str == NULL)
844a1ba9ba4Schristos return TRUE;
845a1ba9ba4Schristos
846a1ba9ba4Schristos /* FIXME: octets_per_byte. */
847a1ba9ba4Schristos hdr = &elf_section_data (sec->output_section)->this_hdr;
848a1ba9ba4Schristos if (hdr->sh_offset == (file_ptr) -1)
849a1ba9ba4Schristos {
850a1ba9ba4Schristos /* We must compress this section. Write output to the
851a1ba9ba4Schristos buffer. */
852a1ba9ba4Schristos contents = hdr->contents;
853a1ba9ba4Schristos if ((sec->output_section->flags & SEC_ELF_COMPRESS) == 0
854a1ba9ba4Schristos || contents == NULL)
855a1ba9ba4Schristos abort ();
856a1ba9ba4Schristos }
857a1ba9ba4Schristos else
858a1ba9ba4Schristos {
859a1ba9ba4Schristos contents = NULL;
860a1ba9ba4Schristos pos = sec->output_section->filepos + sec->output_offset;
861a1ba9ba4Schristos if (bfd_seek (output_bfd, pos, SEEK_SET) != 0)
862a1ba9ba4Schristos return FALSE;
863a1ba9ba4Schristos }
864a1ba9ba4Schristos
865a1ba9ba4Schristos if (! sec_merge_emit (output_bfd, secinfo->first_str, contents,
866a1ba9ba4Schristos sec->output_offset))
867a1ba9ba4Schristos return FALSE;
868a1ba9ba4Schristos
869a1ba9ba4Schristos return TRUE;
870a1ba9ba4Schristos }
871a1ba9ba4Schristos
872a1ba9ba4Schristos /* Adjust an address in the SEC_MERGE section. Given OFFSET within
873a1ba9ba4Schristos *PSEC, this returns the new offset in the adjusted SEC_MERGE
874a1ba9ba4Schristos section and writes the new section back into *PSEC. */
875a1ba9ba4Schristos
876a1ba9ba4Schristos bfd_vma
_bfd_merged_section_offset(bfd * output_bfd ATTRIBUTE_UNUSED,asection ** psec,void * psecinfo,bfd_vma offset)877a1ba9ba4Schristos _bfd_merged_section_offset (bfd *output_bfd ATTRIBUTE_UNUSED, asection **psec,
878a1ba9ba4Schristos void *psecinfo, bfd_vma offset)
879a1ba9ba4Schristos {
880a1ba9ba4Schristos struct sec_merge_sec_info *secinfo;
881a1ba9ba4Schristos struct sec_merge_hash_entry *entry;
882a1ba9ba4Schristos unsigned char *p;
883a1ba9ba4Schristos asection *sec = *psec;
884a1ba9ba4Schristos
885a1ba9ba4Schristos secinfo = (struct sec_merge_sec_info *) psecinfo;
886a1ba9ba4Schristos
887a1ba9ba4Schristos if (!secinfo)
888a1ba9ba4Schristos return offset;
889a1ba9ba4Schristos
890a1ba9ba4Schristos if (offset >= sec->rawsize)
891a1ba9ba4Schristos {
892a1ba9ba4Schristos if (offset > sec->rawsize)
89315d8e94aSchristos _bfd_error_handler
89415d8e94aSchristos /* xgettext:c-format */
895051580eeSchristos (_("%pB: access beyond end of merged section (%" PRId64 ")"),
896051580eeSchristos sec->owner, (int64_t) offset);
897a1ba9ba4Schristos return secinfo->first_str ? sec->size : 0;
898a1ba9ba4Schristos }
899a1ba9ba4Schristos
900a1ba9ba4Schristos if (secinfo->htab->strings)
901a1ba9ba4Schristos {
902a1ba9ba4Schristos if (sec->entsize == 1)
903a1ba9ba4Schristos {
904a1ba9ba4Schristos p = secinfo->contents + offset - 1;
905a1ba9ba4Schristos while (p >= secinfo->contents && *p)
906a1ba9ba4Schristos --p;
907a1ba9ba4Schristos ++p;
908a1ba9ba4Schristos }
909a1ba9ba4Schristos else
910a1ba9ba4Schristos {
911a1ba9ba4Schristos p = secinfo->contents + (offset / sec->entsize) * sec->entsize;
912a1ba9ba4Schristos p -= sec->entsize;
913a1ba9ba4Schristos while (p >= secinfo->contents)
914a1ba9ba4Schristos {
915a1ba9ba4Schristos unsigned int i;
916a1ba9ba4Schristos
917a1ba9ba4Schristos for (i = 0; i < sec->entsize; ++i)
918a1ba9ba4Schristos if (p[i] != '\0')
919a1ba9ba4Schristos break;
920a1ba9ba4Schristos if (i == sec->entsize)
921a1ba9ba4Schristos break;
922a1ba9ba4Schristos p -= sec->entsize;
923a1ba9ba4Schristos }
924a1ba9ba4Schristos p += sec->entsize;
925a1ba9ba4Schristos }
926a1ba9ba4Schristos }
927a1ba9ba4Schristos else
928a1ba9ba4Schristos {
929a1ba9ba4Schristos p = secinfo->contents + (offset / sec->entsize) * sec->entsize;
930a1ba9ba4Schristos }
931a1ba9ba4Schristos entry = sec_merge_hash_lookup (secinfo->htab, (char *) p, 0, FALSE);
932a1ba9ba4Schristos if (!entry)
933a1ba9ba4Schristos {
934a1ba9ba4Schristos if (! secinfo->htab->strings)
935a1ba9ba4Schristos abort ();
936a1ba9ba4Schristos /* This should only happen if somebody points into the padding
937a1ba9ba4Schristos after a NUL character but before next entity. */
938a1ba9ba4Schristos if (*p)
939a1ba9ba4Schristos abort ();
940a1ba9ba4Schristos if (! secinfo->htab->first)
941a1ba9ba4Schristos abort ();
942a1ba9ba4Schristos entry = secinfo->htab->first;
943a1ba9ba4Schristos p = (secinfo->contents + (offset / sec->entsize + 1) * sec->entsize
944a1ba9ba4Schristos - entry->len);
945a1ba9ba4Schristos }
946a1ba9ba4Schristos
947a1ba9ba4Schristos *psec = entry->secinfo->sec;
948a1ba9ba4Schristos return entry->u.index + (secinfo->contents + offset - p);
949a1ba9ba4Schristos }
950a1ba9ba4Schristos
951a1ba9ba4Schristos /* Tidy up when done. */
952a1ba9ba4Schristos
953a1ba9ba4Schristos void
_bfd_merge_sections_free(void * xsinfo)954a1ba9ba4Schristos _bfd_merge_sections_free (void *xsinfo)
955a1ba9ba4Schristos {
956a1ba9ba4Schristos struct sec_merge_info *sinfo;
957a1ba9ba4Schristos
958a1ba9ba4Schristos for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next)
959a1ba9ba4Schristos {
960a1ba9ba4Schristos bfd_hash_table_free (&sinfo->htab->table);
961a1ba9ba4Schristos free (sinfo->htab);
962a1ba9ba4Schristos }
963a1ba9ba4Schristos }
964