libnxflat_bind.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. /****************************************************************************
  2. * binfmt/libnxflat/libnxflat_bind.c
  3. *
  4. * Copyright (C) 2009 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <nuttx/compiler.h>
  40. #include <stdint.h>
  41. #include <string.h>
  42. #include <nxflat.h>
  43. #include <errno.h>
  44. #include <assert.h>
  45. #include <debug.h>
  46. #include <arpa/inet.h>
  47. #include <nuttx/binfmt/nxflat.h>
  48. #include <nuttx/binfmt/symtab.h>
  49. #include "libnxflat.h"
  50. /****************************************************************************
  51. * Pre-processor Definitions
  52. ****************************************************************************/
  53. /* CONFIG_DEBUG_FEATURES, CONFIG_DEBUG_INFO, and CONFIG_DEBUG_BINFMT have to be
  54. * defined or CONFIG_NXFLAT_DUMPBUFFER does nothing.
  55. */
  56. #if !defined(CONFIG_DEBUG_INFO) || !defined (CONFIG_DEBUG_BINFMT)
  57. # undef CONFIG_NXFLAT_DUMPBUFFER
  58. #endif
  59. #ifdef CONFIG_NXFLAT_DUMPBUFFER
  60. # define nxflat_dumpbuffer(m,b,n) binfodumpbuffer(m,b,n)
  61. #else
  62. # define nxflat_dumpbuffer(m,b,n)
  63. #endif
  64. /****************************************************************************
  65. * Private Types
  66. ****************************************************************************/
  67. /****************************************************************************
  68. * Private Data
  69. ****************************************************************************/
  70. /****************************************************************************
  71. * Private Functions
  72. ****************************************************************************/
  73. /****************************************************************************
  74. * Name: nxflat_bindrel32i
  75. *
  76. * Description:
  77. * Perform the NXFLAT_RELOC_TYPE_REL32I binding:
  78. *
  79. * Meaning: Object file contains a 32-bit offset into I-Space at the offset.
  80. * Fixup: Add mapped I-Space address to the offset.
  81. *
  82. * Returned Value:
  83. * 0 (OK) is returned on success and a negated errno is returned on
  84. * failure.
  85. *
  86. ****************************************************************************/
  87. static inline int nxflat_bindrel32i(FAR struct nxflat_loadinfo_s *loadinfo,
  88. uint32_t offset)
  89. {
  90. FAR uint32_t *addr;
  91. binfo("NXFLAT_RELOC_TYPE_REL32I Offset: %08x I-Space: %p\n",
  92. offset, loadinfo->ispace + sizeof(struct nxflat_hdr_s));
  93. if (offset < loadinfo->dsize)
  94. {
  95. addr = (FAR uint32_t *)(offset + loadinfo->dspace->region);
  96. binfo(" Before: %08x\n", *addr);
  97. *addr += (uint32_t)(loadinfo->ispace + sizeof(struct nxflat_hdr_s));
  98. binfo(" After: %08x\n", *addr);
  99. return OK;
  100. }
  101. else
  102. {
  103. berr("Offset: %08 does not lie in D-Space size: %08x\n",
  104. offset, loadinfo->dsize);
  105. return -EINVAL;
  106. }
  107. }
  108. /****************************************************************************
  109. * Name: nxflat_bindrel32d
  110. *
  111. * Description:
  112. * Perform the NXFLAT_RELOC_TYPE_REL32D binding:
  113. *
  114. * Meaning: Object file contains a 32-bit offset into D-Space at the offset.
  115. * Fixup: Add allocated D-Space address to the offset.
  116. *
  117. * Returned Value:
  118. * 0 (OK) is returned on success and a negated errno is returned on
  119. * failure.
  120. *
  121. ****************************************************************************/
  122. static inline int nxflat_bindrel32d(FAR struct nxflat_loadinfo_s *loadinfo,
  123. uint32_t offset)
  124. {
  125. FAR uint32_t *addr;
  126. binfo("NXFLAT_RELOC_TYPE_REL32D Offset: %08x D-Space: %p\n",
  127. offset, loadinfo->dspace->region);
  128. if (offset < loadinfo->dsize)
  129. {
  130. addr = (FAR uint32_t *)(offset + loadinfo->dspace->region);
  131. binfo(" Before: %08x\n", *addr);
  132. *addr += (uint32_t)(loadinfo->dspace->region);
  133. binfo(" After: %08x\n", *addr);
  134. return OK;
  135. }
  136. else
  137. {
  138. berr("Offset: %08 does not lie in D-Space size: %08x\n",
  139. offset, loadinfo->dsize);
  140. return -EINVAL;
  141. }
  142. }
  143. /****************************************************************************
  144. * Name: nxflat_bindrel32id
  145. *
  146. * Description:
  147. * Perform the NXFLAT_RELOC_TYPE_REL32ID binding:
  148. *
  149. * Meaning: Object file contains a 32-bit offset into I-Space at the offset
  150. * that will unfortunately be references relative to the GOT
  151. * Fixup: Add allocated the mapped I-Space address MINUS the allocated
  152. * D-Space address to the offset.
  153. *
  154. * Returned Value:
  155. * 0 (OK) is returned on success and a negated errno is returned on
  156. * failure.
  157. *
  158. ****************************************************************************/
  159. #ifdef NXFLAT_RELOC_TYPE_REL32ID
  160. static inline int nxflat_bindrel32id(FAR struct nxflat_loadinfo_s *loadinfo,
  161. uint32_t offset)
  162. {
  163. FAR uint32_t *addr;
  164. binfo("NXFLAT_RELOC_TYPE_REL32D Offset: %08x D-Space: %p\n",
  165. offset, loadinfo->dspace->region);
  166. if (offset < loadinfo->dsize)
  167. {
  168. addr = (FAR uint32_t *)(offset + loadinfo->dspace->region);
  169. binfo(" Before: %08x\n", *addr);
  170. *addr += ((uint32_t)loadinfo->ispace - (uint32_t)(loadinfo->dspace->region));
  171. binfo(" After: %08x\n", *addr);
  172. return OK;
  173. }
  174. else
  175. {
  176. berr("Offset: %08 does not lie in D-Space size: %08x\n",
  177. offset, loadinfo->dsize);
  178. return -EINVAL;
  179. }
  180. }
  181. #endif
  182. /****************************************************************************
  183. * Name: nxflat_gotrelocs
  184. *
  185. * Description:
  186. * Bind all of the GOT relocations in the loaded module described by
  187. * 'loadinfo'
  188. *
  189. * Returned Value:
  190. * 0 (OK) is returned on success and a negated errno is returned on
  191. * failure.
  192. *
  193. ****************************************************************************/
  194. static inline int nxflat_gotrelocs(FAR struct nxflat_loadinfo_s *loadinfo)
  195. {
  196. FAR struct nxflat_reloc_s *relocs;
  197. FAR struct nxflat_reloc_s reloc;
  198. FAR struct nxflat_hdr_s *hdr;
  199. uint32_t offset;
  200. uint16_t nrelocs;
  201. int ret;
  202. int result;
  203. int i;
  204. /* The NXFLAT header is the first thing at the beginning of the ISpace. */
  205. hdr = (FAR struct nxflat_hdr_s *)loadinfo->ispace;
  206. /* From this, we can get the offset to the list of relocation entries */
  207. offset = ntohl(hdr->h_relocstart);
  208. nrelocs = ntohs(hdr->h_reloccount);
  209. binfo("offset: %08lx nrelocs: %d\n", (long)offset, nrelocs);
  210. /* The value of the relocation list that we get from the header is a
  211. * file offset. We will have to convert this to an offset into the
  212. * DSpace segment to get the pointer to the beginning of the relocation
  213. * list.
  214. */
  215. DEBUGASSERT(offset >= loadinfo->isize);
  216. DEBUGASSERT(offset + nrelocs * sizeof(struct nxflat_reloc_s)
  217. <= (loadinfo->isize + loadinfo->dsize));
  218. relocs = (FAR struct nxflat_reloc_s *)
  219. (offset - loadinfo->isize + loadinfo->dspace->region);
  220. binfo("isize: %08lx dpsace: %p relocs: %p\n",
  221. (long)loadinfo->isize, loadinfo->dspace->region, relocs);
  222. /* All relocations are performed within the D-Space allocation. If
  223. * CONFIG_ARCH_ADDRENV=y, then that D-Space allocation lies in an address
  224. * environment that may not be in place. So, in that case, we must call
  225. * nxflat_addrenv_select to temporarily instantiate that address space
  226. * before the relocations can be performed.
  227. */
  228. #ifdef CONFIG_ARCH_ADDRENV
  229. ret = nxflat_addrenv_select(loadinfo);
  230. if (ret < 0)
  231. {
  232. berr("ERROR: nxflat_addrenv_select() failed: %d\n", ret);
  233. return ret;
  234. }
  235. #endif
  236. /* Now, traverse the relocation list of and bind each GOT relocation. */
  237. ret = OK; /* Assume success */
  238. for (i = 0; i < nrelocs; i++)
  239. {
  240. /* Handle the relocation by the relocation type */
  241. #ifdef CONFIG_CAN_PASS_STRUCTS
  242. reloc = *relocs++;
  243. #else
  244. memcpy(&reloc, relocs, sizeof(struct nxflat_reloc_s));
  245. relocs++;
  246. #endif
  247. result = OK;
  248. switch (NXFLAT_RELOC_TYPE(reloc.r_info))
  249. {
  250. /* NXFLAT_RELOC_TYPE_REL32I Meaning: Object file contains a 32-bit offset
  251. * into I-Space at the offset.
  252. * Fixup: Add mapped I-Space address to the offset.
  253. */
  254. case NXFLAT_RELOC_TYPE_REL32I:
  255. {
  256. result = nxflat_bindrel32i(loadinfo, NXFLAT_RELOC_OFFSET(reloc.r_info));
  257. }
  258. break;
  259. /* NXFLAT_RELOC_TYPE_REL32D Meaning: Object file contains a 32-bit offset
  260. * into D-Space at the offset.
  261. * Fixup: Add allocated D-Space address to the
  262. * offset.
  263. */
  264. case NXFLAT_RELOC_TYPE_REL32D:
  265. {
  266. result = nxflat_bindrel32d(loadinfo, NXFLAT_RELOC_OFFSET(reloc.r_info));
  267. }
  268. break;
  269. /* NXFLAT_RELOC_TYPE_REL32ID Meaning: Object file contains a 32-bit offset
  270. * into I-Space at the offset that will
  271. * unfortunately be references relative
  272. * to the GOT
  273. * Fixup: Add allocated the mapped I-Space
  274. * address MINUS the allocated D-Space
  275. * address to the offset.
  276. */
  277. #ifdef NXFLAT_RELOC_TYPE_REL32ID
  278. case NXFLAT_RELOC_TYPE_REL32ID:
  279. {
  280. result = nxflat_bindrel32id(loadinfo, NXFLAT_RELOC_OFFSET(reloc.r_info));
  281. }
  282. break;
  283. #endif
  284. default:
  285. {
  286. berr("ERROR: Unrecognized relocation type: %d\n", NXFLAT_RELOC_TYPE(reloc.r_info));
  287. result = -EINVAL;
  288. }
  289. break;
  290. }
  291. /* Check for failures */
  292. if (result < 0 && ret == OK)
  293. {
  294. ret = result;
  295. }
  296. }
  297. /* Dump the relocation got */
  298. #ifdef CONFIG_NXFLAT_DUMPBUFFER
  299. if (ret == OK && nrelocs > 0)
  300. {
  301. relocs = (FAR struct nxflat_reloc_s *)(offset - loadinfo->isize + loadinfo->dspace->region);
  302. nxflat_dumpbuffer("GOT", (FAR const uint8_t *)relocs, nrelocs * sizeof(struct nxflat_reloc_s));
  303. }
  304. #endif
  305. /* Restore the original address environment */
  306. #ifdef CONFIG_ARCH_ADDRENV
  307. ret = nxflat_addrenv_restore(loadinfo);
  308. if (ret < 0)
  309. {
  310. berr("ERROR: nxflat_addrenv_restore() failed: %d\n", ret);
  311. }
  312. #endif
  313. return ret;
  314. }
  315. /****************************************************************************
  316. * Name: nxflat_bindimports
  317. *
  318. * Description:
  319. * Bind the imported symbol names in the loaded module described by
  320. * 'loadinfo' using the exported symbol values provided by 'symtab'
  321. *
  322. * Returned Value:
  323. * 0 (OK) is returned on success and a negated errno is returned on
  324. * failure.
  325. *
  326. ****************************************************************************/
  327. static inline int nxflat_bindimports(FAR struct nxflat_loadinfo_s *loadinfo,
  328. FAR const struct symtab_s *exports,
  329. int nexports)
  330. {
  331. FAR struct nxflat_import_s *imports;
  332. FAR struct nxflat_hdr_s *hdr;
  333. FAR const struct symtab_s *symbol;
  334. char *symname;
  335. uint32_t offset;
  336. uint16_t nimports;
  337. #ifdef CONFIG_ARCH_ADDRENV
  338. int ret;
  339. #endif
  340. int i;
  341. /* The NXFLAT header is the first thing at the beginning of the ISpace. */
  342. hdr = (FAR struct nxflat_hdr_s *)loadinfo->ispace;
  343. /* From this, we can get the offset to the list of symbols imported by
  344. * this module and the number of symbols imported by this module.
  345. */
  346. offset = ntohl(hdr->h_importsymbols);
  347. nimports = ntohs(hdr->h_importcount);
  348. binfo("Imports offset: %08x nimports: %d\n", offset, nimports);
  349. /* The import[] table resides within the D-Space allocation. If
  350. * CONFIG_ARCH_ADDRENV=y, then that D-Space allocation lies in an address
  351. * environment that may not be in place. So, in that case, we must call
  352. * nxflat_addrenv_select to temporarily instantiate that address space
  353. * before the import[] table can be modified.
  354. */
  355. #ifdef CONFIG_ARCH_ADDRENV
  356. ret = nxflat_addrenv_select(loadinfo);
  357. if (ret < 0)
  358. {
  359. berr("ERROR: nxflat_addrenv_select() failed: %d\n", ret);
  360. return ret;
  361. }
  362. #endif
  363. /* Verify that this module requires imported symbols */
  364. if (offset != 0 && nimports > 0)
  365. {
  366. /* It does.. make sure that exported symbols are provided */
  367. DEBUGASSERT(exports && nexports > 0);
  368. /* If non-zero, the value of the imported symbol list that we get
  369. * from the header is a file offset. We will have to convert this
  370. * to an offset into the DSpace segment to get the pointer to the
  371. * beginning of the imported symbol list.
  372. */
  373. DEBUGASSERT(offset >= loadinfo->isize &&
  374. offset < loadinfo->isize + loadinfo->dsize);
  375. imports = (FAR struct nxflat_import_s *)
  376. (offset - loadinfo->isize + loadinfo->dspace->region);
  377. /* Now, traverse the list of imported symbols and attempt to bind
  378. * each symbol to the value exported by from the exported symbol
  379. * table.
  380. */
  381. for (i = 0; i < nimports; i++)
  382. {
  383. binfo("Import[%d] (%08p) offset: %08x func: %08x\n",
  384. i, &imports[i], imports[i].i_funcname, imports[i].i_funcaddress);
  385. /* Get a pointer to the imported symbol name. The name itself
  386. * lies in the TEXT segment. But the reference to the name
  387. * lies in DATA segment. Therefore, the name reference should
  388. * have been relocated when the module was loaded.
  389. */
  390. offset = imports[i].i_funcname;
  391. DEBUGASSERT(offset < loadinfo->isize);
  392. symname = (FAR char *)(offset + loadinfo->ispace + sizeof(struct nxflat_hdr_s));
  393. /* Find the exported symbol value for this this symbol name. */
  394. #ifdef CONFIG_SYMTAB_ORDEREDBYNAME
  395. symbol = symtab_findorderedbyname(exports, symname, nexports);
  396. #else
  397. symbol = symtab_findbyname(exports, symname, nexports);
  398. #endif
  399. if (!symbol)
  400. {
  401. berr("Exported symbol \"%s\" not found\n", symname);
  402. #ifdef CONFIG_ARCH_ADDRENV
  403. (void)nxflat_addrenv_restore(loadinfo);
  404. #endif
  405. return -ENOENT;
  406. }
  407. /* And put this into the module's import structure. */
  408. imports[i].i_funcaddress = (uint32_t)symbol->sym_value;
  409. binfo("Bound import[%d] (%08p) to export '%s' (%08x)\n",
  410. i, &imports[i], symname, imports[i].i_funcaddress);
  411. }
  412. }
  413. /* Dump the relocation import table */
  414. #ifdef CONFIG_NXFLAT_DUMPBUFFER
  415. if (nimports > 0)
  416. {
  417. nxflat_dumpbuffer("Imports", (FAR const uint8_t *)imports, nimports * sizeof(struct nxflat_import_s));
  418. }
  419. #endif
  420. /* Restore the original address environment */
  421. #ifdef CONFIG_ARCH_ADDRENV
  422. ret = nxflat_addrenv_restore(loadinfo);
  423. if (ret < 0)
  424. {
  425. berr("ERROR: nxflat_addrenv_restore() failed: %d\n", ret);
  426. }
  427. return ret;
  428. #else
  429. return OK;
  430. #endif
  431. }
  432. /****************************************************************************
  433. * Name: nxflat_clearbss
  434. *
  435. * Description:
  436. * Clear uninitialized .bss memory
  437. *
  438. * Returned Value:
  439. * 0 (OK) is returned on success and a negated errno is returned on
  440. * failure.
  441. *
  442. ****************************************************************************/
  443. static inline int nxflat_clearbss(FAR struct nxflat_loadinfo_s *loadinfo)
  444. {
  445. #ifdef CONFIG_ARCH_ADDRENV
  446. int ret;
  447. #endif
  448. /* .bss resides within the D-Space allocation. If CONFIG_ARCH_ADDRENV=y, then
  449. * that D-Space allocation lies in an address environment that may not be
  450. * in place. So, in that case, we must call nxflat_addrenv_select to
  451. * temporarily instantiate that address space before the .bss can be
  452. * accessed.
  453. */
  454. #ifdef CONFIG_ARCH_ADDRENV
  455. ret = nxflat_addrenv_select(loadinfo);
  456. if (ret < 0)
  457. {
  458. berr("ERROR: nxflat_addrenv_select() failed: %d\n", ret);
  459. return ret;
  460. }
  461. #endif
  462. /* Zero the BSS area */
  463. memset((FAR void *)(loadinfo->dspace->region + loadinfo->datasize), 0,
  464. loadinfo->bsssize);
  465. /* Restore the original address environment */
  466. #ifdef CONFIG_ARCH_ADDRENV
  467. ret = nxflat_addrenv_restore(loadinfo);
  468. if (ret < 0)
  469. {
  470. berr("ERROR: nxflat_addrenv_restore() failed: %d\n", ret);
  471. }
  472. return ret;
  473. #else
  474. return OK;
  475. #endif
  476. }
  477. /****************************************************************************
  478. * Public Functions
  479. ****************************************************************************/
  480. /****************************************************************************
  481. * Name: nxflat_bind
  482. *
  483. * Description:
  484. * Bind the imported symbol names in the loaded module described by
  485. * 'loadinfo' using the exported symbol values provided by 'symtab'.
  486. * After binding the module, clear the BSS region (which held the relocation
  487. * data) in preparation for execution.
  488. *
  489. * Returned Value:
  490. * 0 (OK) is returned on success and a negated errno is returned on
  491. * failure.
  492. *
  493. ****************************************************************************/
  494. int nxflat_bind(FAR struct nxflat_loadinfo_s *loadinfo,
  495. FAR const struct symtab_s *exports, int nexports)
  496. {
  497. /* Bind the imported symbol, absolute relocations separately. This is done
  498. * before the standard relocations because that logic may modify the
  499. * import list (for the better hopefully, but we don't want to depend on it).
  500. */
  501. int ret = nxflat_bindimports(loadinfo, exports, nexports);
  502. if (ret == OK)
  503. {
  504. /* Then bind all GOT relocations */
  505. ret = nxflat_gotrelocs(loadinfo);
  506. if (ret == OK)
  507. {
  508. /* Zero the BSS area, trashing the relocations that lived in that
  509. * space in the loaded file.
  510. */
  511. ret = nxflat_clearbss(loadinfo);
  512. }
  513. }
  514. return ret;
  515. }