elf-strtab.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /* ELF strtab with GC and suffix merging support.
  2. Copyright (C) 2001-2015 Free Software Foundation, Inc.
  3. Written by Jakub Jelinek <jakub@redhat.com>.
  4. This file is part of BFD, the Binary File Descriptor library.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
  16. MA 02110-1301, USA. */
  17. #include "sysdep.h"
  18. #include "bfd.h"
  19. #include "libbfd.h"
  20. #include "elf-bfd.h"
  21. #include "hashtab.h"
  22. #include "libiberty.h"
  23. /* An entry in the strtab hash table. */
  24. struct elf_strtab_hash_entry
  25. {
  26. struct bfd_hash_entry root;
  27. /* Length of this entry. This includes the zero terminator. */
  28. int len;
  29. unsigned int refcount;
  30. union {
  31. /* Index within the merged section. */
  32. bfd_size_type index;
  33. /* Entry this is a suffix of (if len < 0). */
  34. struct elf_strtab_hash_entry *suffix;
  35. } u;
  36. };
  37. /* The strtab hash table. */
  38. struct elf_strtab_hash
  39. {
  40. struct bfd_hash_table table;
  41. /* Next available index. */
  42. bfd_size_type size;
  43. /* Number of array entries alloced. */
  44. bfd_size_type alloced;
  45. /* Final strtab size. */
  46. bfd_size_type sec_size;
  47. /* Array of pointers to strtab entries. */
  48. struct elf_strtab_hash_entry **array;
  49. };
  50. /* Routine to create an entry in a section merge hashtab. */
  51. static struct bfd_hash_entry *
  52. elf_strtab_hash_newfunc (struct bfd_hash_entry *entry,
  53. struct bfd_hash_table *table,
  54. const char *string)
  55. {
  56. /* Allocate the structure if it has not already been allocated by a
  57. subclass. */
  58. if (entry == NULL)
  59. entry = (struct bfd_hash_entry *)
  60. bfd_hash_allocate (table, sizeof (struct elf_strtab_hash_entry));
  61. if (entry == NULL)
  62. return NULL;
  63. /* Call the allocation method of the superclass. */
  64. entry = bfd_hash_newfunc (entry, table, string);
  65. if (entry)
  66. {
  67. /* Initialize the local fields. */
  68. struct elf_strtab_hash_entry *ret;
  69. ret = (struct elf_strtab_hash_entry *) entry;
  70. ret->u.index = -1;
  71. ret->refcount = 0;
  72. ret->len = 0;
  73. }
  74. return entry;
  75. }
  76. /* Create a new hash table. */
  77. struct elf_strtab_hash *
  78. _bfd_elf_strtab_init (void)
  79. {
  80. struct elf_strtab_hash *table;
  81. bfd_size_type amt = sizeof (struct elf_strtab_hash);
  82. table = (struct elf_strtab_hash *) bfd_malloc (amt);
  83. if (table == NULL)
  84. return NULL;
  85. if (!bfd_hash_table_init (&table->table, elf_strtab_hash_newfunc,
  86. sizeof (struct elf_strtab_hash_entry)))
  87. {
  88. free (table);
  89. return NULL;
  90. }
  91. table->sec_size = 0;
  92. table->size = 1;
  93. table->alloced = 64;
  94. amt = sizeof (struct elf_strtab_hasn_entry *);
  95. table->array = (struct elf_strtab_hash_entry **)
  96. bfd_malloc (table->alloced * amt);
  97. if (table->array == NULL)
  98. {
  99. free (table);
  100. return NULL;
  101. }
  102. table->array[0] = NULL;
  103. return table;
  104. }
  105. /* Free a strtab. */
  106. void
  107. _bfd_elf_strtab_free (struct elf_strtab_hash *tab)
  108. {
  109. bfd_hash_table_free (&tab->table);
  110. free (tab->array);
  111. free (tab);
  112. }
  113. /* Get the index of an entity in a hash table, adding it if it is not
  114. already present. */
  115. bfd_size_type
  116. _bfd_elf_strtab_add (struct elf_strtab_hash *tab,
  117. const char *str,
  118. bfd_boolean copy)
  119. {
  120. register struct elf_strtab_hash_entry *entry;
  121. /* We handle this specially, since we don't want to do refcounting
  122. on it. */
  123. if (*str == '\0')
  124. return 0;
  125. BFD_ASSERT (tab->sec_size == 0);
  126. entry = (struct elf_strtab_hash_entry *)
  127. bfd_hash_lookup (&tab->table, str, TRUE, copy);
  128. if (entry == NULL)
  129. return (bfd_size_type) -1;
  130. entry->refcount++;
  131. if (entry->len == 0)
  132. {
  133. entry->len = strlen (str) + 1;
  134. /* 2G strings lose. */
  135. BFD_ASSERT (entry->len > 0);
  136. if (tab->size == tab->alloced)
  137. {
  138. bfd_size_type amt = sizeof (struct elf_strtab_hash_entry *);
  139. tab->alloced *= 2;
  140. tab->array = (struct elf_strtab_hash_entry **)
  141. bfd_realloc_or_free (tab->array, tab->alloced * amt);
  142. if (tab->array == NULL)
  143. return (bfd_size_type) -1;
  144. }
  145. entry->u.index = tab->size++;
  146. tab->array[entry->u.index] = entry;
  147. }
  148. return entry->u.index;
  149. }
  150. void
  151. _bfd_elf_strtab_addref (struct elf_strtab_hash *tab, bfd_size_type idx)
  152. {
  153. if (idx == 0 || idx == (bfd_size_type) -1)
  154. return;
  155. BFD_ASSERT (tab->sec_size == 0);
  156. BFD_ASSERT (idx < tab->size);
  157. ++tab->array[idx]->refcount;
  158. }
  159. void
  160. _bfd_elf_strtab_delref (struct elf_strtab_hash *tab, bfd_size_type idx)
  161. {
  162. if (idx == 0 || idx == (bfd_size_type) -1)
  163. return;
  164. BFD_ASSERT (tab->sec_size == 0);
  165. BFD_ASSERT (idx < tab->size);
  166. BFD_ASSERT (tab->array[idx]->refcount > 0);
  167. --tab->array[idx]->refcount;
  168. }
  169. unsigned int
  170. _bfd_elf_strtab_refcount (struct elf_strtab_hash *tab, bfd_size_type idx)
  171. {
  172. return tab->array[idx]->refcount;
  173. }
  174. void
  175. _bfd_elf_strtab_clear_all_refs (struct elf_strtab_hash *tab)
  176. {
  177. bfd_size_type idx;
  178. for (idx = 1; idx < tab->size; idx++)
  179. tab->array[idx]->refcount = 0;
  180. }
  181. /* Downsizes strtab. Entries from IDX up to the current size are
  182. removed from the array. */
  183. void
  184. _bfd_elf_strtab_restore_size (struct elf_strtab_hash *tab, bfd_size_type idx)
  185. {
  186. bfd_size_type curr_size = tab->size;
  187. BFD_ASSERT (tab->sec_size == 0);
  188. BFD_ASSERT (idx <= curr_size);
  189. tab->size = idx;
  190. for (; idx < curr_size; ++idx)
  191. {
  192. /* We don't remove entries from the hash table, just set their
  193. REFCOUNT to zero. Setting LEN zero will result in the size
  194. growing if the entry is added again. See _bfd_elf_strtab_add. */
  195. tab->array[idx]->refcount = 0;
  196. tab->array[idx]->len = 0;
  197. }
  198. }
  199. bfd_size_type
  200. _bfd_elf_strtab_size (struct elf_strtab_hash *tab)
  201. {
  202. return tab->sec_size ? tab->sec_size : tab->size;
  203. }
  204. bfd_size_type
  205. _bfd_elf_strtab_offset (struct elf_strtab_hash *tab, bfd_size_type idx)
  206. {
  207. struct elf_strtab_hash_entry *entry;
  208. if (idx == 0)
  209. return 0;
  210. BFD_ASSERT (idx < tab->size);
  211. BFD_ASSERT (tab->sec_size);
  212. entry = tab->array[idx];
  213. BFD_ASSERT (entry->refcount > 0);
  214. entry->refcount--;
  215. return tab->array[idx]->u.index;
  216. }
  217. bfd_boolean
  218. _bfd_elf_strtab_emit (register bfd *abfd, struct elf_strtab_hash *tab)
  219. {
  220. bfd_size_type off = 1, i;
  221. if (bfd_bwrite ("", 1, abfd) != 1)
  222. return FALSE;
  223. for (i = 1; i < tab->size; ++i)
  224. {
  225. register const char *str;
  226. register unsigned int len;
  227. BFD_ASSERT (tab->array[i]->refcount == 0);
  228. len = tab->array[i]->len;
  229. if ((int) len < 0)
  230. continue;
  231. str = tab->array[i]->root.string;
  232. if (bfd_bwrite (str, len, abfd) != len)
  233. return FALSE;
  234. off += len;
  235. }
  236. BFD_ASSERT (off == tab->sec_size);
  237. return TRUE;
  238. }
  239. /* Compare two elf_strtab_hash_entry structures. Called via qsort. */
  240. static int
  241. strrevcmp (const void *a, const void *b)
  242. {
  243. struct elf_strtab_hash_entry *A = *(struct elf_strtab_hash_entry **) a;
  244. struct elf_strtab_hash_entry *B = *(struct elf_strtab_hash_entry **) b;
  245. unsigned int lenA = A->len;
  246. unsigned int lenB = B->len;
  247. const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
  248. const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
  249. int l = lenA < lenB ? lenA : lenB;
  250. while (l)
  251. {
  252. if (*s != *t)
  253. return (int) *s - (int) *t;
  254. s--;
  255. t--;
  256. l--;
  257. }
  258. return lenA - lenB;
  259. }
  260. static inline int
  261. is_suffix (const struct elf_strtab_hash_entry *A,
  262. const struct elf_strtab_hash_entry *B)
  263. {
  264. if (A->len <= B->len)
  265. /* B cannot be a suffix of A unless A is equal to B, which is guaranteed
  266. not to be equal by the hash table. */
  267. return 0;
  268. return memcmp (A->root.string + (A->len - B->len),
  269. B->root.string, B->len - 1) == 0;
  270. }
  271. /* This function assigns final string table offsets for used strings,
  272. merging strings matching suffixes of longer strings if possible. */
  273. void
  274. _bfd_elf_strtab_finalize (struct elf_strtab_hash *tab)
  275. {
  276. struct elf_strtab_hash_entry **array, **a, *e;
  277. bfd_size_type size, amt;
  278. /* GCC 2.91.66 (egcs-1.1.2) on i386 miscompiles this function when i is
  279. a 64-bit bfd_size_type: a 64-bit target or --enable-64-bit-bfd.
  280. Besides, indexing with a long long wouldn't give anything but extra
  281. cycles. */
  282. size_t i;
  283. /* Sort the strings by suffix and length. */
  284. amt = tab->size * sizeof (struct elf_strtab_hash_entry *);
  285. array = (struct elf_strtab_hash_entry **) bfd_malloc (amt);
  286. if (array == NULL)
  287. goto alloc_failure;
  288. for (i = 1, a = array; i < tab->size; ++i)
  289. {
  290. e = tab->array[i];
  291. if (e->refcount)
  292. {
  293. *a++ = e;
  294. /* Adjust the length to not include the zero terminator. */
  295. e->len -= 1;
  296. }
  297. else
  298. e->len = 0;
  299. }
  300. size = a - array;
  301. if (size != 0)
  302. {
  303. qsort (array, size, sizeof (struct elf_strtab_hash_entry *), strrevcmp);
  304. /* Loop over the sorted array and merge suffixes. Start from the
  305. end because we want eg.
  306. s1 -> "d"
  307. s2 -> "bcd"
  308. s3 -> "abcd"
  309. to end up as
  310. s3 -> "abcd"
  311. s2 _____^
  312. s1 _______^
  313. ie. we don't want s1 pointing into the old s2. */
  314. e = *--a;
  315. e->len += 1;
  316. while (--a >= array)
  317. {
  318. struct elf_strtab_hash_entry *cmp = *a;
  319. cmp->len += 1;
  320. if (is_suffix (e, cmp))
  321. {
  322. cmp->u.suffix = e;
  323. cmp->len = -cmp->len;
  324. }
  325. else
  326. e = cmp;
  327. }
  328. }
  329. alloc_failure:
  330. if (array)
  331. free (array);
  332. /* Assign positions to the strings we want to keep. */
  333. size = 1;
  334. for (i = 1; i < tab->size; ++i)
  335. {
  336. e = tab->array[i];
  337. if (e->refcount && e->len > 0)
  338. {
  339. e->u.index = size;
  340. size += e->len;
  341. }
  342. }
  343. tab->sec_size = size;
  344. /* Adjust the rest. */
  345. for (i = 1; i < tab->size; ++i)
  346. {
  347. e = tab->array[i];
  348. if (e->refcount && e->len < 0)
  349. e->u.index = e->u.suffix->u.index + (e->u.suffix->len + e->len);
  350. }
  351. }