modlib_symbols.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /****************************************************************************
  2. * libs/libc/modlib/modlib_symbols.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 <stdlib.h>
  25. #include <string.h>
  26. #include <errno.h>
  27. #include <debug.h>
  28. #include <nuttx/lib/modlib.h>
  29. #include "modlib/modlib.h"
  30. /****************************************************************************
  31. * Pre-processor Definitions
  32. ****************************************************************************/
  33. /* Return values search for exported modules */
  34. #define SYM_NOT_FOUND 0
  35. #define SYM_FOUND 1
  36. /****************************************************************************
  37. * Private Types
  38. ****************************************************************************/
  39. struct mod_exportinfo_s
  40. {
  41. FAR const char *name; /* Symbol name to find */
  42. FAR struct module_s *modp; /* The module that needs the symbol */
  43. FAR const struct symtab_s *symbol; /* Symbol info returned (if found) */
  44. };
  45. /****************************************************************************
  46. * Private Functions
  47. ****************************************************************************/
  48. /****************************************************************************
  49. * Name: modlib_symname
  50. *
  51. * Description:
  52. * Get the symbol name in loadinfo->iobuffer[].
  53. *
  54. * Returned Value:
  55. * 0 (OK) is returned on success and a negated errno is returned on
  56. * failure.
  57. *
  58. * EINVAL - There is something inconsistent in the symbol table (should
  59. * only happen if the file is corrupted).
  60. * ESRCH - Symbol has no name
  61. *
  62. ****************************************************************************/
  63. static int modlib_symname(FAR struct mod_loadinfo_s *loadinfo,
  64. FAR const Elf_Sym *sym)
  65. {
  66. FAR uint8_t *buffer;
  67. off_t offset;
  68. size_t readlen;
  69. size_t bytesread;
  70. int ret;
  71. /* Get the file offset to the string that is the name of the symbol. The
  72. * st_name member holds an offset into the file's symbol string table.
  73. */
  74. if (sym->st_name == 0)
  75. {
  76. berr("ERROR: Symbol has no name\n");
  77. return -ESRCH;
  78. }
  79. offset = loadinfo->shdr[loadinfo->strtabidx].sh_offset + sym->st_name;
  80. /* Loop until we get the entire symbol name into memory */
  81. bytesread = 0;
  82. for (; ; )
  83. {
  84. /* Get the number of bytes to read */
  85. readlen = loadinfo->buflen - bytesread;
  86. if (offset + readlen > loadinfo->filelen)
  87. {
  88. if (loadinfo->filelen <= offset)
  89. {
  90. berr("ERROR: At end of file\n");
  91. return -EINVAL;
  92. }
  93. readlen = loadinfo->filelen - offset;
  94. }
  95. /* Read that number of bytes into the array */
  96. buffer = &loadinfo->iobuffer[bytesread];
  97. ret = modlib_read(loadinfo, buffer, readlen, offset);
  98. if (ret < 0)
  99. {
  100. berr("ERROR: modlib_read failed: %d\n", ret);
  101. return ret;
  102. }
  103. bytesread += readlen;
  104. /* Did we read the NUL terminator? */
  105. if (memchr(buffer, '\0', readlen) != NULL)
  106. {
  107. /* Yes, the buffer contains a NUL terminator. */
  108. return OK;
  109. }
  110. /* No.. then we have to read more */
  111. ret = modlib_reallocbuffer(loadinfo, CONFIG_MODLIB_BUFFERINCR);
  112. if (ret < 0)
  113. {
  114. berr("ERROR: mod_reallocbuffer failed: %d\n", ret);
  115. return ret;
  116. }
  117. }
  118. /* We will not get here */
  119. return OK;
  120. }
  121. /****************************************************************************
  122. * Name: modlib_symcallback
  123. *
  124. * Description:
  125. * modlib_registry_foreach() callback function. Test if the provided
  126. * module, modp, exports the symbol of interest. If so, return that symbol
  127. * value and setup the module dependency relationship.
  128. *
  129. * Returned Value:
  130. * 0 (OK) is returned on success and a negated errno is returned on
  131. * failure.
  132. *
  133. ****************************************************************************/
  134. static int modlib_symcallback(FAR struct module_s *modp, FAR void *arg)
  135. {
  136. FAR struct mod_exportinfo_s *exportinfo = (FAR struct mod_exportinfo_s *)
  137. arg;
  138. int ret;
  139. /* Check if this module exports a symbol of that name */
  140. #ifdef CONFIG_SYMTAB_ORDEREDBYNAME
  141. exportinfo->symbol = symtab_findorderedbyname(modp->modinfo.exports,
  142. exportinfo->name,
  143. modp->modinfo.nexports);
  144. #else
  145. exportinfo->symbol = symtab_findbyname(modp->modinfo.exports,
  146. exportinfo->name,
  147. modp->modinfo.nexports);
  148. #endif
  149. if (exportinfo->symbol != NULL)
  150. {
  151. /* Yes.. save the dependency relationship and return SYM_FOUND to
  152. * stop the traversal.
  153. */
  154. ret = modlib_depend(exportinfo->modp, modp);
  155. if (ret < 0)
  156. {
  157. berr("ERROR: modlib_depend failed: %d\n", ret);
  158. return ret;
  159. }
  160. return SYM_FOUND;
  161. }
  162. return SYM_NOT_FOUND;
  163. }
  164. /****************************************************************************
  165. * Public Functions
  166. ****************************************************************************/
  167. /****************************************************************************
  168. * Name: modlib_findsymtab
  169. *
  170. * Description:
  171. * Find the symbol table section.
  172. *
  173. * Returned Value:
  174. * 0 (OK) is returned on success and a negated errno is returned on
  175. * failure.
  176. *
  177. ****************************************************************************/
  178. int modlib_findsymtab(FAR struct mod_loadinfo_s *loadinfo)
  179. {
  180. int i;
  181. /* Find the symbol table section header and its associated string table */
  182. for (i = 1; i < loadinfo->ehdr.e_shnum; i++)
  183. {
  184. if (loadinfo->shdr[i].sh_type == SHT_SYMTAB)
  185. {
  186. loadinfo->symtabidx = i;
  187. loadinfo->strtabidx = loadinfo->shdr[i].sh_link;
  188. break;
  189. }
  190. }
  191. /* Verify that there is a symbol and string table */
  192. if (loadinfo->symtabidx == 0)
  193. {
  194. berr("ERROR: No symbols in ELF file\n");
  195. return -EINVAL;
  196. }
  197. return OK;
  198. }
  199. /****************************************************************************
  200. * Name: modlib_readsym
  201. *
  202. * Description:
  203. * Read the ELF symbol structure at the specified index into memory.
  204. *
  205. * Input Parameters:
  206. * loadinfo - Load state information
  207. * index - Symbol table index
  208. * sym - Location to return the table entry
  209. *
  210. * Returned Value:
  211. * 0 (OK) is returned on success and a negated errno is returned on
  212. * failure.
  213. *
  214. ****************************************************************************/
  215. int modlib_readsym(FAR struct mod_loadinfo_s *loadinfo, int index,
  216. FAR Elf_Sym *sym)
  217. {
  218. FAR Elf_Shdr *symtab = &loadinfo->shdr[loadinfo->symtabidx];
  219. off_t offset;
  220. /* Verify that the symbol table index lies within symbol table */
  221. if (index < 0 || index > (symtab->sh_size / sizeof(Elf_Sym)))
  222. {
  223. berr("ERROR: Bad relocation symbol index: %d\n", index);
  224. return -EINVAL;
  225. }
  226. /* Get the file offset to the symbol table entry */
  227. offset = symtab->sh_offset + sizeof(Elf_Sym) * index;
  228. /* And, finally, read the symbol table entry into memory */
  229. return modlib_read(loadinfo, (FAR uint8_t *)sym, sizeof(Elf_Sym), offset);
  230. }
  231. /****************************************************************************
  232. * Name: modlib_symvalue
  233. *
  234. * Description:
  235. * Get the value of a symbol. The updated value of the symbol is returned
  236. * in the st_value field of the symbol table entry.
  237. *
  238. * Input Parameters:
  239. * modp - Module state information
  240. * loadinfo - Load state information
  241. * sym - Symbol table entry (value might be undefined)
  242. *
  243. * Returned Value:
  244. * 0 (OK) is returned on success and a negated errno is returned on
  245. * failure.
  246. *
  247. * EINVAL - There is something inconsistent in the symbol table (should
  248. * only happen if the file is corrupted).
  249. * ENOSYS - Symbol lies in common
  250. * ESRCH - Symbol has no name
  251. * ENOENT - Symbol undefined and not provided via a symbol table
  252. *
  253. ****************************************************************************/
  254. int modlib_symvalue(FAR struct module_s *modp,
  255. FAR struct mod_loadinfo_s *loadinfo, FAR Elf_Sym *sym)
  256. {
  257. FAR const struct symtab_s *symbol;
  258. struct mod_exportinfo_s exportinfo;
  259. uintptr_t secbase;
  260. int nsymbols;
  261. int ret;
  262. switch (sym->st_shndx)
  263. {
  264. case SHN_COMMON:
  265. {
  266. /* NuttX ELF modules should be compiled with -fno-common. */
  267. berr("ERROR: SHN_COMMON: Re-compile with -fno-common\n");
  268. return -ENOSYS;
  269. }
  270. case SHN_ABS:
  271. {
  272. /* st_value already holds the correct value */
  273. binfo("SHN_ABS: st_value=%08lx\n", (long)sym->st_value);
  274. return OK;
  275. }
  276. case SHN_UNDEF:
  277. {
  278. /* Get the name of the undefined symbol */
  279. ret = modlib_symname(loadinfo, sym);
  280. if (ret < 0)
  281. {
  282. /* There are a few relocations for a few architectures that do
  283. * no depend upon a named symbol. We don't know if that is the
  284. * case here, but return and special error to the caller to
  285. * indicate the nameless symbol.
  286. */
  287. berr("ERROR: SHN_UNDEF: Failed to get symbol name: %d\n", ret);
  288. return ret;
  289. }
  290. /* First check if the symbol is exported by an installed module.
  291. * Newest modules are installed at the head of the list. Therefore,
  292. * if the symbol is exported by numerous modules, then the most
  293. * recently installed will take precedence.
  294. */
  295. exportinfo.name = (FAR const char *)loadinfo->iobuffer;
  296. exportinfo.modp = modp;
  297. exportinfo.symbol = NULL;
  298. ret = modlib_registry_foreach(modlib_symcallback,
  299. (FAR void *)&exportinfo);
  300. if (ret < 0)
  301. {
  302. berr("ERROR: modlib_symcallback failed: \n", ret);
  303. return ret;
  304. }
  305. symbol = exportinfo.symbol;
  306. /* If the symbol is not exported by any module, then check if the
  307. * base code exports a symbol of this name.
  308. */
  309. if (symbol == NULL)
  310. {
  311. modlib_getsymtab(&symbol, &nsymbols);
  312. #ifdef CONFIG_SYMTAB_ORDEREDBYNAME
  313. symbol = symtab_findorderedbyname(symbol, exportinfo.name,
  314. nsymbols);
  315. #else
  316. symbol = symtab_findbyname(symbol, exportinfo.name,
  317. nsymbols);
  318. #endif
  319. }
  320. /* Was the symbol found from any exporter? */
  321. if (symbol == NULL)
  322. {
  323. berr("ERROR: SHN_UNDEF: Exported symbol \"%s\" not found\n",
  324. loadinfo->iobuffer);
  325. return -ENOENT;
  326. }
  327. /* Yes... add the exported symbol value to the ELF symbol tablei
  328. * entry
  329. */
  330. binfo("SHN_UNDEF: name=%s %08x+%08x=%08x\n",
  331. loadinfo->iobuffer, sym->st_value, symbol->sym_value,
  332. sym->st_value + symbol->sym_value);
  333. sym->st_value += ((uintptr_t)symbol->sym_value);
  334. }
  335. break;
  336. default:
  337. {
  338. secbase = loadinfo->shdr[sym->st_shndx].sh_addr;
  339. binfo("Other: %08x+%08x=%08x\n",
  340. sym->st_value, secbase, sym->st_value + secbase);
  341. sym->st_value += secbase;
  342. }
  343. break;
  344. }
  345. return OK;
  346. }