modlib_bind.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. /****************************************************************************
  2. * libs/libc/modlib/modlib_bind.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /****************************************************************************
  21. * Included Files
  22. ****************************************************************************/
  23. #include <nuttx/config.h>
  24. #include <stdint.h>
  25. #include <string.h>
  26. #include <errno.h>
  27. #include <assert.h>
  28. #include <debug.h>
  29. #include <nuttx/elf.h>
  30. #include <nuttx/lib/modlib.h>
  31. #include "libc.h"
  32. #include "modlib/modlib.h"
  33. /****************************************************************************
  34. * Private Types
  35. ****************************************************************************/
  36. /* REVISIT: This naming breaks the NuttX coding standard, but is consistent
  37. * with legacy naming of other ELF types.
  38. */
  39. typedef struct
  40. {
  41. dq_entry_t entry;
  42. Elf_Sym sym;
  43. int idx;
  44. } Elf_SymCache;
  45. /****************************************************************************
  46. * Private Functions
  47. ****************************************************************************/
  48. /****************************************************************************
  49. * Name: modlib_readrels
  50. *
  51. * Description:
  52. * Read the (ELF_Rel structure * buffer count) into memory.
  53. *
  54. ****************************************************************************/
  55. static inline int modlib_readrels(FAR struct mod_loadinfo_s *loadinfo,
  56. FAR const Elf_Shdr *relsec,
  57. int index, FAR Elf_Rel *rels,
  58. int count)
  59. {
  60. off_t offset;
  61. int size;
  62. /* Verify that the symbol table index lies within symbol table */
  63. if (index < 0 || index > (relsec->sh_size / sizeof(Elf_Rel)))
  64. {
  65. berr("ERROR: Bad relocation symbol index: %d\n", index);
  66. return -EINVAL;
  67. }
  68. /* Get the file offset to the symbol table entry */
  69. offset = sizeof(Elf_Rel) * index;
  70. size = sizeof(Elf_Rel) * count;
  71. if (offset + size > relsec->sh_size)
  72. {
  73. size = relsec->sh_size - offset;
  74. }
  75. /* And, finally, read the symbol table entry into memory */
  76. return modlib_read(loadinfo, (FAR uint8_t *)rels, size,
  77. relsec->sh_offset + offset);
  78. }
  79. /****************************************************************************
  80. * Name: modlib_readrelas
  81. *
  82. * Description:
  83. * Read the (ELF_Rela structure * buffer count) into memory.
  84. *
  85. ****************************************************************************/
  86. static inline int modlib_readrelas(FAR struct mod_loadinfo_s *loadinfo,
  87. FAR const Elf_Shdr *relsec,
  88. int index, FAR Elf_Rela *relas,
  89. int count)
  90. {
  91. off_t offset;
  92. int size;
  93. /* Verify that the symbol table index lies within symbol table */
  94. if (index < 0 || index > (relsec->sh_size / sizeof(Elf_Rela)))
  95. {
  96. berr("ERROR: Bad relocation symbol index: %d\n", index);
  97. return -EINVAL;
  98. }
  99. /* Get the file offset to the symbol table entry */
  100. offset = sizeof(Elf_Rela) * index;
  101. size = sizeof(Elf_Rela) * count;
  102. if (offset + size > relsec->sh_size)
  103. {
  104. size = relsec->sh_size - offset;
  105. }
  106. /* And, finally, read the symbol table entry into memory */
  107. return modlib_read(loadinfo, (FAR uint8_t *)relas, size,
  108. relsec->sh_offset + offset);
  109. }
  110. /****************************************************************************
  111. * Name: modlib_relocate and modlib_relocateadd
  112. *
  113. * Description:
  114. * Perform all relocations associated with a section.
  115. *
  116. * Returned Value:
  117. * 0 (OK) is returned on success and a negated errno is returned on
  118. * failure.
  119. *
  120. ****************************************************************************/
  121. static int modlib_relocate(FAR struct module_s *modp,
  122. FAR struct mod_loadinfo_s *loadinfo, int relidx)
  123. {
  124. FAR Elf_Shdr *relsec = &loadinfo->shdr[relidx];
  125. FAR Elf_Shdr *dstsec = &loadinfo->shdr[relsec->sh_info];
  126. FAR Elf_Rel *rels;
  127. FAR Elf_Rel *rel;
  128. FAR Elf_SymCache *cache;
  129. FAR Elf_Sym *sym;
  130. FAR dq_entry_t *e;
  131. dq_queue_t q;
  132. uintptr_t addr;
  133. int symidx;
  134. int ret;
  135. int i;
  136. int j;
  137. rels = lib_malloc(CONFIG_MODLIB_RELOCATION_BUFFERCOUNT * sizeof(Elf_Rel));
  138. if (!rels)
  139. {
  140. berr("Failed to allocate memory for elf relocation rels\n");
  141. return -ENOMEM;
  142. }
  143. dq_init(&q);
  144. /* Examine each relocation in the section. 'relsec' is the section
  145. * containing the relations. 'dstsec' is the section containing the data
  146. * to be relocated.
  147. */
  148. ret = OK;
  149. for (i = j = 0; i < relsec->sh_size / sizeof(Elf_Rel); i++)
  150. {
  151. /* Read the relocation entry into memory */
  152. rel = &rels[i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT];
  153. if (!(i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT))
  154. {
  155. ret = modlib_readrels(loadinfo, relsec, i, rels,
  156. CONFIG_MODLIB_RELOCATION_BUFFERCOUNT);
  157. if (ret < 0)
  158. {
  159. berr("ERROR: Section %d reloc %d: "
  160. "Failed to read relocation entry: %d\n",
  161. relidx, i, ret);
  162. break;
  163. }
  164. }
  165. /* Get the symbol table index for the relocation. This is contained
  166. * in a bit-field within the r_info element.
  167. */
  168. symidx = ELF_R_SYM(rel->r_info);
  169. /* First try the cache */
  170. sym = NULL;
  171. for (e = dq_peek(&q); e; e = dq_next(e))
  172. {
  173. cache = (FAR Elf_SymCache *)e;
  174. if (cache->idx == symidx)
  175. {
  176. dq_rem(&cache->entry, &q);
  177. dq_addfirst(&cache->entry, &q);
  178. sym = &cache->sym;
  179. break;
  180. }
  181. }
  182. /* If the symbol was not found in the cache, we will need to read the
  183. * symbol from the file.
  184. */
  185. if (sym == NULL)
  186. {
  187. if (j < CONFIG_MODLIB_SYMBOL_CACHECOUNT)
  188. {
  189. cache = lib_malloc(sizeof(Elf_SymCache));
  190. if (!cache)
  191. {
  192. berr("Failed to allocate memory for elf symbols\n");
  193. ret = -ENOMEM;
  194. break;
  195. }
  196. j++;
  197. }
  198. else
  199. {
  200. cache = (FAR Elf_SymCache *)dq_remlast(&q);
  201. }
  202. sym = &cache->sym;
  203. /* Read the symbol table entry into memory */
  204. ret = modlib_readsym(loadinfo, symidx, sym);
  205. if (ret < 0)
  206. {
  207. berr("ERROR: Section %d reloc %d: "
  208. "Failed to read symbol[%d]: %d\n",
  209. relidx, i, symidx, ret);
  210. lib_free(cache);
  211. break;
  212. }
  213. /* Get the value of the symbol (in sym.st_value) */
  214. ret = modlib_symvalue(modp, loadinfo, sym);
  215. if (ret < 0)
  216. {
  217. /* The special error -ESRCH is returned only in one condition:
  218. * The symbol has no name.
  219. *
  220. * There are a few relocations for a few architectures that do
  221. * no depend upon a named symbol. We don't know if that is the
  222. * case here, but we will use a NULL symbol pointer to indicate
  223. * that case to up_relocate(). That function can then do what
  224. * is best.
  225. */
  226. if (ret == -ESRCH)
  227. {
  228. berr("ERROR: Section %d reloc %d: "
  229. "Undefined symbol[%d] has no name: %d\n",
  230. relidx, i, symidx, ret);
  231. }
  232. else
  233. {
  234. berr("ERROR: Section %d reloc %d: "
  235. "Failed to get value of symbol[%d]: %d\n",
  236. relidx, i, symidx, ret);
  237. lib_free(cache);
  238. break;
  239. }
  240. }
  241. cache->idx = symidx;
  242. dq_addfirst(&cache->entry, &q);
  243. }
  244. if (sym->st_shndx == SHN_UNDEF && sym->st_name == 0)
  245. {
  246. sym = NULL;
  247. }
  248. /* Calculate the relocation address. */
  249. if (rel->r_offset < 0 ||
  250. rel->r_offset > dstsec->sh_size - sizeof(uint32_t))
  251. {
  252. berr("ERROR: Section %d reloc %d: "
  253. "Relocation address out of range, offset %d size %d\n",
  254. relidx, i, rel->r_offset, dstsec->sh_size);
  255. ret = -EINVAL;
  256. break;
  257. }
  258. addr = dstsec->sh_addr + rel->r_offset;
  259. /* Now perform the architecture-specific relocation */
  260. ret = up_relocate(rel, sym, addr);
  261. if (ret < 0)
  262. {
  263. berr("ERROR: Section %d reloc %d: Relocation failed: %d\n",
  264. relidx, i, ret);
  265. break;
  266. }
  267. }
  268. lib_free(rels);
  269. while ((e = dq_peek(&q)))
  270. {
  271. dq_rem(e, &q);
  272. lib_free(e);
  273. }
  274. return ret;
  275. }
  276. static int modlib_relocateadd(FAR struct module_s *modp,
  277. FAR struct mod_loadinfo_s *loadinfo, int relidx)
  278. {
  279. FAR Elf_Shdr *relsec = &loadinfo->shdr[relidx];
  280. FAR Elf_Shdr *dstsec = &loadinfo->shdr[relsec->sh_info];
  281. FAR Elf_Rela *relas;
  282. FAR Elf_Rela *rela;
  283. FAR Elf_SymCache *cache;
  284. FAR Elf_Sym *sym;
  285. FAR dq_entry_t *e;
  286. dq_queue_t q;
  287. uintptr_t addr;
  288. int symidx;
  289. int ret;
  290. int i;
  291. int j;
  292. relas = lib_malloc(CONFIG_MODLIB_RELOCATION_BUFFERCOUNT *
  293. sizeof(Elf_Rela));
  294. if (!relas)
  295. {
  296. berr("Failed to allocate memory for elf relocation relas\n");
  297. return -ENOMEM;
  298. }
  299. dq_init(&q);
  300. /* Examine each relocation in the section. 'relsec' is the section
  301. * containing the relations. 'dstsec' is the section containing the data
  302. * to be relocated.
  303. */
  304. ret = OK;
  305. for (i = j = 0; i < relsec->sh_size / sizeof(Elf_Rela); i++)
  306. {
  307. /* Read the relocation entry into memory */
  308. rela = &relas[i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT];
  309. if (!(i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT))
  310. {
  311. ret = modlib_readrelas(loadinfo, relsec, i, relas,
  312. CONFIG_MODLIB_RELOCATION_BUFFERCOUNT);
  313. if (ret < 0)
  314. {
  315. berr("ERROR: Section %d reloc %d: "
  316. "Failed to read relocation entry: %d\n",
  317. relidx, i, ret);
  318. break;
  319. }
  320. }
  321. /* Get the symbol table index for the relocation. This is contained
  322. * in a bit-field within the r_info element.
  323. */
  324. symidx = ELF_R_SYM(rela->r_info);
  325. /* First try the cache */
  326. sym = NULL;
  327. for (e = dq_peek(&q); e; e = dq_next(e))
  328. {
  329. cache = (FAR Elf_SymCache *)e;
  330. if (cache->idx == symidx)
  331. {
  332. dq_rem(&cache->entry, &q);
  333. dq_addfirst(&cache->entry, &q);
  334. sym = &cache->sym;
  335. break;
  336. }
  337. }
  338. /* If the symbol was not found in the cache, we will need to read the
  339. * symbol from the file.
  340. */
  341. if (sym == NULL)
  342. {
  343. if (j < CONFIG_MODLIB_SYMBOL_CACHECOUNT)
  344. {
  345. cache = lib_malloc(sizeof(Elf_SymCache));
  346. if (!cache)
  347. {
  348. berr("Failed to allocate memory for elf symbols\n");
  349. ret = -ENOMEM;
  350. break;
  351. }
  352. j++;
  353. }
  354. else
  355. {
  356. cache = (FAR Elf_SymCache *)dq_remlast(&q);
  357. }
  358. sym = &cache->sym;
  359. /* Read the symbol table entry into memory */
  360. ret = modlib_readsym(loadinfo, symidx, sym);
  361. if (ret < 0)
  362. {
  363. berr("ERROR: Section %d reloc %d: "
  364. "Failed to read symbol[%d]: %d\n",
  365. relidx, i, symidx, ret);
  366. lib_free(cache);
  367. break;
  368. }
  369. /* Get the value of the symbol (in sym.st_value) */
  370. ret = modlib_symvalue(modp, loadinfo, sym);
  371. if (ret < 0)
  372. {
  373. /* The special error -ESRCH is returned only in one condition:
  374. * The symbol has no name.
  375. *
  376. * There are a few relocations for a few architectures that do
  377. * no depend upon a named symbol. We don't know if that is the
  378. * case here, but we will use a NULL symbol pointer to indicate
  379. * that case to up_relocate(). That function can then do what
  380. * is best.
  381. */
  382. if (ret == -ESRCH)
  383. {
  384. berr("ERROR: Section %d reloc %d: "
  385. "Undefined symbol[%d] has no name: %d\n",
  386. relidx, i, symidx, ret);
  387. }
  388. else
  389. {
  390. berr("ERROR: Section %d reloc %d: "
  391. "Failed to get value of symbol[%d]: %d\n",
  392. relidx, i, symidx, ret);
  393. lib_free(cache);
  394. break;
  395. }
  396. }
  397. cache->idx = symidx;
  398. dq_addfirst(&cache->entry, &q);
  399. }
  400. if (sym->st_shndx == SHN_UNDEF && sym->st_name == 0)
  401. {
  402. sym = NULL;
  403. }
  404. /* Calculate the relocation address. */
  405. if (rela->r_offset < 0 ||
  406. rela->r_offset > dstsec->sh_size - sizeof(uint32_t))
  407. {
  408. berr("ERROR: Section %d reloc %d: "
  409. "Relocation address out of range, offset %d size %d\n",
  410. relidx, i, rela->r_offset, dstsec->sh_size);
  411. ret = -EINVAL;
  412. break;
  413. }
  414. addr = dstsec->sh_addr + rela->r_offset;
  415. /* Now perform the architecture-specific relocation */
  416. ret = up_relocateadd(rela, sym, addr);
  417. if (ret < 0)
  418. {
  419. berr("ERROR: Section %d reloc %d: Relocation failed: %d\n",
  420. relidx, i, ret);
  421. break;
  422. }
  423. }
  424. lib_free(relas);
  425. while ((e = dq_peek(&q)))
  426. {
  427. dq_rem(e, &q);
  428. lib_free(e);
  429. }
  430. return ret;
  431. }
  432. /****************************************************************************
  433. * Public Functions
  434. ****************************************************************************/
  435. /****************************************************************************
  436. * Name: modlib_bind
  437. *
  438. * Description:
  439. * Bind the imported symbol names in the loaded module described by
  440. * 'loadinfo' using the exported symbol values provided by
  441. * modlib_setsymtab().
  442. *
  443. * Input Parameters:
  444. * modp - Module state information
  445. * loadinfo - Load state information
  446. *
  447. * Returned Value:
  448. * 0 (OK) is returned on success and a negated errno is returned on
  449. * failure.
  450. *
  451. ****************************************************************************/
  452. int modlib_bind(FAR struct module_s *modp,
  453. FAR struct mod_loadinfo_s *loadinfo)
  454. {
  455. int ret;
  456. int i;
  457. /* Find the symbol and string tables */
  458. ret = modlib_findsymtab(loadinfo);
  459. if (ret < 0)
  460. {
  461. return ret;
  462. }
  463. /* Allocate an I/O buffer. This buffer is used by mod_symname() to
  464. * accumulate the variable length symbol name.
  465. */
  466. ret = modlib_allocbuffer(loadinfo);
  467. if (ret < 0)
  468. {
  469. berr("ERROR: modlib_allocbuffer failed: %d\n", ret);
  470. return -ENOMEM;
  471. }
  472. /* Process relocations in every allocated section */
  473. for (i = 1; i < loadinfo->ehdr.e_shnum; i++)
  474. {
  475. /* Get the index to the relocation section */
  476. int infosec = loadinfo->shdr[i].sh_info;
  477. if (infosec >= loadinfo->ehdr.e_shnum)
  478. {
  479. continue;
  480. }
  481. /* Make sure that the section is allocated. We can't relocate
  482. * sections that were not loaded into memory.
  483. */
  484. if ((loadinfo->shdr[infosec].sh_flags & SHF_ALLOC) == 0)
  485. {
  486. continue;
  487. }
  488. /* Process the relocations by type */
  489. if (loadinfo->shdr[i].sh_type == SHT_REL)
  490. {
  491. ret = modlib_relocate(modp, loadinfo, i);
  492. }
  493. else if (loadinfo->shdr[i].sh_type == SHT_RELA)
  494. {
  495. ret = modlib_relocateadd(modp, loadinfo, i);
  496. }
  497. if (ret < 0)
  498. {
  499. break;
  500. }
  501. }
  502. /* Ensure that the I and D caches are coherent before starting the newly
  503. * loaded module by cleaning the D cache (i.e., flushing the D cache
  504. * contents to memory and invalidating the I cache).
  505. */
  506. up_coherent_dcache(loadinfo->textalloc, loadinfo->textsize);
  507. up_coherent_dcache(loadinfo->datastart, loadinfo->datasize);
  508. return ret;
  509. }