libnxflat_bind.c 19 KB

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