elf-strtab.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /* ELF strtab with GC and suffix merging support.
  2. Copyright (C) 2001-2022 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. size_t size;
  43. /* Number of array entries alloced. */
  44. size_t 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. size_t 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. size_t
  116. _bfd_elf_strtab_add (struct elf_strtab_hash *tab,
  117. const char *str,
  118. bool 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 (size_t) -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 (size_t) -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, size_t idx)
  152. {
  153. if (idx == 0 || idx == (size_t) -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, size_t idx)
  161. {
  162. if (idx == 0 || idx == (size_t) -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, size_t 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. size_t idx;
  178. for (idx = 1; idx < tab->size; idx++)
  179. tab->array[idx]->refcount = 0;
  180. }
  181. /* Save strtab refcounts prior to adding --as-needed library. */
  182. struct strtab_save
  183. {
  184. size_t size;
  185. unsigned int refcount[1];
  186. };
  187. void *
  188. _bfd_elf_strtab_save (struct elf_strtab_hash *tab)
  189. {
  190. struct strtab_save *save;
  191. size_t idx, size;
  192. size = sizeof (*save) + (tab->size - 1) * sizeof (save->refcount[0]);
  193. save = bfd_malloc (size);
  194. if (save == NULL)
  195. return save;
  196. save->size = tab->size;
  197. for (idx = 1; idx < tab->size; idx++)
  198. save->refcount[idx] = tab->array[idx]->refcount;
  199. return save;
  200. }
  201. /* Restore strtab refcounts on finding --as-needed library not needed. */
  202. void
  203. _bfd_elf_strtab_restore (struct elf_strtab_hash *tab, void *buf)
  204. {
  205. size_t idx, curr_size = tab->size, save_size;
  206. struct strtab_save *save = (struct strtab_save *) buf;
  207. BFD_ASSERT (tab->sec_size == 0);
  208. save_size = 1;
  209. if (save != NULL)
  210. save_size = save->size;
  211. BFD_ASSERT (save_size <= curr_size);
  212. tab->size = save_size;
  213. for (idx = 1; idx < save_size; ++idx)
  214. tab->array[idx]->refcount = save->refcount[idx];
  215. for (; idx < curr_size; ++idx)
  216. {
  217. /* We don't remove entries from the hash table, just set their
  218. REFCOUNT to zero. Setting LEN zero will result in the size
  219. growing if the entry is added again. See _bfd_elf_strtab_add. */
  220. tab->array[idx]->refcount = 0;
  221. tab->array[idx]->len = 0;
  222. }
  223. }
  224. bfd_size_type
  225. _bfd_elf_strtab_size (struct elf_strtab_hash *tab)
  226. {
  227. return tab->sec_size ? tab->sec_size : tab->size;
  228. }
  229. bfd_size_type
  230. _bfd_elf_strtab_len (struct elf_strtab_hash *tab)
  231. {
  232. return tab->size;
  233. }
  234. bfd_size_type
  235. _bfd_elf_strtab_offset (struct elf_strtab_hash *tab, size_t idx)
  236. {
  237. struct elf_strtab_hash_entry *entry;
  238. if (idx == 0)
  239. return 0;
  240. BFD_ASSERT (idx < tab->size);
  241. BFD_ASSERT (tab->sec_size);
  242. entry = tab->array[idx];
  243. BFD_ASSERT (entry->refcount > 0);
  244. entry->refcount--;
  245. return tab->array[idx]->u.index;
  246. }
  247. const char *
  248. _bfd_elf_strtab_str (struct elf_strtab_hash *tab, size_t idx,
  249. bfd_size_type *offset)
  250. {
  251. if (idx == 0)
  252. return NULL;
  253. BFD_ASSERT (idx < tab->size);
  254. BFD_ASSERT (tab->sec_size);
  255. if (tab->array[idx]->refcount == 0)
  256. return NULL;
  257. if (offset)
  258. *offset = tab->array[idx]->u.index;
  259. return tab->array[idx]->root.string;
  260. }
  261. bool
  262. _bfd_elf_strtab_emit (register bfd *abfd, struct elf_strtab_hash *tab)
  263. {
  264. bfd_size_type off = 1;
  265. size_t i;
  266. if (bfd_bwrite ("", 1, abfd) != 1)
  267. return false;
  268. for (i = 1; i < tab->size; ++i)
  269. {
  270. register const char *str;
  271. register unsigned int len;
  272. BFD_ASSERT (tab->array[i]->refcount == 0);
  273. len = tab->array[i]->len;
  274. if ((int) len < 0)
  275. continue;
  276. str = tab->array[i]->root.string;
  277. if (bfd_bwrite (str, len, abfd) != len)
  278. return false;
  279. off += len;
  280. }
  281. BFD_ASSERT (off == tab->sec_size);
  282. return true;
  283. }
  284. /* Compare two elf_strtab_hash_entry structures. Called via qsort.
  285. Won't ever return zero as all entries differ, so there is no issue
  286. with qsort stability here. */
  287. static int
  288. strrevcmp (const void *a, const void *b)
  289. {
  290. struct elf_strtab_hash_entry *A = *(struct elf_strtab_hash_entry **) a;
  291. struct elf_strtab_hash_entry *B = *(struct elf_strtab_hash_entry **) b;
  292. unsigned int lenA = A->len;
  293. unsigned int lenB = B->len;
  294. const unsigned char *s = (const unsigned char *) A->root.string + lenA - 1;
  295. const unsigned char *t = (const unsigned char *) B->root.string + lenB - 1;
  296. int l = lenA < lenB ? lenA : lenB;
  297. while (l)
  298. {
  299. if (*s != *t)
  300. return (int) *s - (int) *t;
  301. s--;
  302. t--;
  303. l--;
  304. }
  305. return lenA - lenB;
  306. }
  307. static inline int
  308. is_suffix (const struct elf_strtab_hash_entry *A,
  309. const struct elf_strtab_hash_entry *B)
  310. {
  311. if (A->len <= B->len)
  312. /* B cannot be a suffix of A unless A is equal to B, which is guaranteed
  313. not to be equal by the hash table. */
  314. return 0;
  315. return memcmp (A->root.string + (A->len - B->len),
  316. B->root.string, B->len - 1) == 0;
  317. }
  318. /* This function assigns final string table offsets for used strings,
  319. merging strings matching suffixes of longer strings if possible. */
  320. void
  321. _bfd_elf_strtab_finalize (struct elf_strtab_hash *tab)
  322. {
  323. struct elf_strtab_hash_entry **array, **a, *e;
  324. bfd_size_type amt, sec_size;
  325. size_t size, i;
  326. /* Sort the strings by suffix and length. */
  327. amt = tab->size;
  328. amt *= sizeof (struct elf_strtab_hash_entry *);
  329. array = (struct elf_strtab_hash_entry **) bfd_malloc (amt);
  330. if (array == NULL)
  331. goto alloc_failure;
  332. for (i = 1, a = array; i < tab->size; ++i)
  333. {
  334. e = tab->array[i];
  335. if (e->refcount)
  336. {
  337. *a++ = e;
  338. /* Adjust the length to not include the zero terminator. */
  339. e->len -= 1;
  340. }
  341. else
  342. e->len = 0;
  343. }
  344. size = a - array;
  345. if (size != 0)
  346. {
  347. qsort (array, size, sizeof (struct elf_strtab_hash_entry *), strrevcmp);
  348. /* Loop over the sorted array and merge suffixes. Start from the
  349. end because we want eg.
  350. s1 -> "d"
  351. s2 -> "bcd"
  352. s3 -> "abcd"
  353. to end up as
  354. s3 -> "abcd"
  355. s2 _____^
  356. s1 _______^
  357. ie. we don't want s1 pointing into the old s2. */
  358. e = *--a;
  359. e->len += 1;
  360. while (--a >= array)
  361. {
  362. struct elf_strtab_hash_entry *cmp = *a;
  363. cmp->len += 1;
  364. if (is_suffix (e, cmp))
  365. {
  366. cmp->u.suffix = e;
  367. cmp->len = -cmp->len;
  368. }
  369. else
  370. e = cmp;
  371. }
  372. }
  373. alloc_failure:
  374. free (array);
  375. /* Assign positions to the strings we want to keep. */
  376. sec_size = 1;
  377. for (i = 1; i < tab->size; ++i)
  378. {
  379. e = tab->array[i];
  380. if (e->refcount && e->len > 0)
  381. {
  382. e->u.index = sec_size;
  383. sec_size += e->len;
  384. }
  385. }
  386. tab->sec_size = sec_size;
  387. /* Adjust the rest. */
  388. for (i = 1; i < tab->size; ++i)
  389. {
  390. e = tab->array[i];
  391. if (e->refcount && e->len < 0)
  392. e->u.index = e->u.suffix->u.index + (e->u.suffix->len + e->len);
  393. }
  394. }