dyld.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. /* loader-dyld.c -- dynamic linking on darwin and OS X
  2. Copyright (C) 1998-2000, 2004, 2006-2008, 2011-2015 Free Software
  3. Foundation, Inc.
  4. Written by Peter O'Gorman, 1998
  5. NOTE: The canonical source of this file is maintained with the
  6. GNU Libtool package. Report bugs to bug-libtool@gnu.org.
  7. GNU Libltdl is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU Lesser General Public
  9. License as published by the Free Software Foundation; either
  10. version 2 of the License, or (at your option) any later version.
  11. As a special exception to the GNU Lesser General Public License,
  12. if you distribute this file as part of a program or library that
  13. is built using GNU Libtool, you may include this file under the
  14. same distribution terms that you use for the rest of that program.
  15. GNU Libltdl is distributed in the hope that it will be useful,
  16. but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. GNU Lesser General Public License for more details.
  19. You should have received a copy of the GNU Lesser General Public
  20. License along with GNU Libltdl; see the file COPYING.LIB. If not, a
  21. copy can be downloaded from http://www.gnu.org/licenses/lgpl.html,
  22. or obtained by writing to the Free Software Foundation, Inc.,
  23. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  24. */
  25. #include "lt__private.h"
  26. #include "lt_dlloader.h"
  27. /* Use the preprocessor to rename non-static symbols to avoid namespace
  28. collisions when the loader code is statically linked into libltdl.
  29. Use the "<module_name>_LTX_" prefix so that the symbol addresses can
  30. be fetched from the preloaded symbol list by lt_dlsym(): */
  31. #define get_vtable dyld_LTX_get_vtable
  32. LT_BEGIN_C_DECLS
  33. LT_SCOPE lt_dlvtable *get_vtable (lt_user_data loader_data);
  34. LT_END_C_DECLS
  35. /* Boilerplate code to set up the vtable for hooking this loader into
  36. libltdl's loader list: */
  37. static int vl_init (lt_user_data loader_data);
  38. static int vl_exit (lt_user_data loader_data);
  39. static lt_module vm_open (lt_user_data loader_data, const char *filename,
  40. lt_dladvise advise);
  41. static int vm_close (lt_user_data loader_data, lt_module module);
  42. static void * vm_sym (lt_user_data loader_data, lt_module module,
  43. const char *symbolname);
  44. static lt_dlvtable *vtable = 0;
  45. /* Return the vtable for this loader, only the name and sym_prefix
  46. attributes (plus the virtual function implementations, obviously)
  47. change between loaders. */
  48. lt_dlvtable *
  49. get_vtable (lt_user_data loader_data)
  50. {
  51. if (!vtable)
  52. {
  53. vtable = lt__zalloc (sizeof *vtable);
  54. }
  55. if (vtable && !vtable->name)
  56. {
  57. vtable->name = "lt_dyld";
  58. vtable->sym_prefix = "_";
  59. vtable->dlloader_init = vl_init;
  60. vtable->module_open = vm_open;
  61. vtable->module_close = vm_close;
  62. vtable->find_sym = vm_sym;
  63. vtable->dlloader_exit = vl_exit;
  64. vtable->dlloader_data = loader_data;
  65. vtable->priority = LT_DLLOADER_APPEND;
  66. }
  67. if (vtable && (vtable->dlloader_data != loader_data))
  68. {
  69. LT__SETERROR (INIT_LOADER);
  70. return 0;
  71. }
  72. return vtable;
  73. }
  74. /* --- IMPLEMENTATION --- */
  75. #if defined HAVE_MACH_O_DYLD_H
  76. # if !defined __APPLE_CC__ && !defined __MWERKS__ && !defined __private_extern__
  77. /* Is this correct? Does it still function properly? */
  78. # define __private_extern__ extern
  79. # endif
  80. # include <mach-o/dyld.h>
  81. #endif
  82. #include <mach-o/getsect.h>
  83. /* We have to put some stuff here that isn't in older dyld.h files */
  84. #if !defined ENUM_DYLD_BOOL
  85. # define ENUM_DYLD_BOOL
  86. # undef FALSE
  87. # undef TRUE
  88. enum DYLD_BOOL {
  89. FALSE,
  90. TRUE
  91. };
  92. #endif
  93. #if !defined LC_REQ_DYLD
  94. # define LC_REQ_DYLD 0x80000000
  95. #endif
  96. #if !defined LC_LOAD_WEAK_DYLIB
  97. # define LC_LOAD_WEAK_DYLIB (0x18 | LC_REQ_DYLD)
  98. #endif
  99. #if !defined NSADDIMAGE_OPTION_NONE
  100. # define NSADDIMAGE_OPTION_NONE 0x0
  101. #endif
  102. #if !defined NSADDIMAGE_OPTION_RETURN_ON_ERROR
  103. # define NSADDIMAGE_OPTION_RETURN_ON_ERROR 0x1
  104. #endif
  105. #if !defined NSADDIMAGE_OPTION_WITH_SEARCHING
  106. # define NSADDIMAGE_OPTION_WITH_SEARCHING 0x2
  107. #endif
  108. #if !defined NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
  109. # define NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED 0x4
  110. #endif
  111. #if !defined NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME
  112. # define NSADDIMAGE_OPTION_MATCH_FILENAME_BY_INSTALLNAME 0x8
  113. #endif
  114. #if !defined NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
  115. # define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND 0x0
  116. #endif
  117. #if !defined NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW
  118. # define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW 0x1
  119. #endif
  120. #if !defined NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY
  121. # define NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_FULLY 0x2
  122. #endif
  123. #if !defined NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
  124. # define NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR 0x4
  125. #endif
  126. #define LT__SYMLOOKUP_OPTS (NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW \
  127. | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR)
  128. #if defined __BIG_ENDIAN__
  129. # define LT__MAGIC MH_MAGIC
  130. #else
  131. # define LT__MAGIC MH_CIGAM
  132. #endif
  133. #define DYLD__SETMYERROR(errmsg) LT__SETERRORSTR (dylderror (errmsg))
  134. #define DYLD__SETERROR(errcode) DYLD__SETMYERROR (LT__STRERROR (errcode))
  135. typedef struct mach_header mach_header;
  136. typedef struct dylib_command dylib_command;
  137. static const char *dylderror (const char *errmsg);
  138. static const mach_header *lt__nsmodule_get_header (NSModule module);
  139. static const char *lt__header_get_instnam (const mach_header *mh);
  140. static const mach_header *lt__match_loadedlib (const char *name);
  141. static NSSymbol lt__linkedlib_symbol (const char *symname, const mach_header *mh);
  142. static const mach_header *(*lt__addimage) (const char *image_name,
  143. unsigned long options) = 0;
  144. static NSSymbol (*lt__image_symbol) (const mach_header *image,
  145. const char *symbolName,
  146. unsigned long options) = 0;
  147. static enum DYLD_BOOL (*lt__image_symbol_p) (const mach_header *image,
  148. const char *symbolName) = 0;
  149. static enum DYLD_BOOL (*lt__module_export) (NSModule module) = 0;
  150. static int dyld_cannot_close = 0;
  151. /* A function called through the vtable when this loader is no
  152. longer needed by the application. */
  153. static int
  154. vl_exit (lt_user_data loader_data LT__UNUSED)
  155. {
  156. vtable = NULL;
  157. return 0;
  158. }
  159. /* A function called through the vtable to initialise this loader. */
  160. static int
  161. vl_init (lt_user_data loader_data)
  162. {
  163. int errors = 0;
  164. if (! dyld_cannot_close)
  165. {
  166. if (!_dyld_present ())
  167. {
  168. ++errors;
  169. }
  170. else
  171. {
  172. (void) _dyld_func_lookup ("__dyld_NSAddImage",
  173. (unsigned long*) &lt__addimage);
  174. (void) _dyld_func_lookup ("__dyld_NSLookupSymbolInImage",
  175. (unsigned long*)&lt__image_symbol);
  176. (void) _dyld_func_lookup ("__dyld_NSIsSymbolNameDefinedInImage",
  177. (unsigned long*) &lt__image_symbol_p);
  178. (void) _dyld_func_lookup ("__dyld_NSMakePrivateModulePublic",
  179. (unsigned long*) &lt__module_export);
  180. dyld_cannot_close = lt_dladderror ("can't close a dylib");
  181. }
  182. }
  183. return errors;
  184. }
  185. /* A function called through the vtable to open a module with this
  186. loader. Returns an opaque representation of the newly opened
  187. module for processing with this loader's other vtable functions. */
  188. static lt_module
  189. vm_open (lt_user_data loader_data, const char *filename,
  190. lt_dladvise advise LT__UNUSED)
  191. {
  192. lt_module module = 0;
  193. NSObjectFileImage ofi = 0;
  194. if (!filename)
  195. {
  196. return (lt_module) -1;
  197. }
  198. switch (NSCreateObjectFileImageFromFile (filename, &ofi))
  199. {
  200. case NSObjectFileImageSuccess:
  201. module = NSLinkModule (ofi, filename, NSLINKMODULE_OPTION_RETURN_ON_ERROR
  202. | NSLINKMODULE_OPTION_PRIVATE
  203. | NSLINKMODULE_OPTION_BINDNOW);
  204. NSDestroyObjectFileImage (ofi);
  205. if (module)
  206. {
  207. lt__module_export (module);
  208. }
  209. break;
  210. case NSObjectFileImageInappropriateFile:
  211. if (lt__image_symbol_p && lt__image_symbol)
  212. {
  213. module = (lt_module) lt__addimage(filename,
  214. NSADDIMAGE_OPTION_RETURN_ON_ERROR);
  215. }
  216. break;
  217. case NSObjectFileImageFailure:
  218. case NSObjectFileImageArch:
  219. case NSObjectFileImageFormat:
  220. case NSObjectFileImageAccess:
  221. /*NOWORK*/
  222. break;
  223. }
  224. if (!module)
  225. {
  226. DYLD__SETERROR (CANNOT_OPEN);
  227. }
  228. return module;
  229. }
  230. /* A function called through the vtable when a particular module
  231. should be unloaded. */
  232. static int
  233. vm_close (lt_user_data loader_data, lt_module module)
  234. {
  235. int errors = 0;
  236. if (module != (lt_module) -1)
  237. {
  238. const mach_header *mh = (const mach_header *) module;
  239. int flags = 0;
  240. if (mh->magic == LT__MAGIC)
  241. {
  242. lt_dlseterror (dyld_cannot_close);
  243. ++errors;
  244. }
  245. else
  246. {
  247. /* Currently, if a module contains c++ static destructors and it
  248. is unloaded, we get a segfault in atexit(), due to compiler and
  249. dynamic loader differences of opinion, this works around that. */
  250. if ((const struct section *) NULL !=
  251. getsectbynamefromheader (lt__nsmodule_get_header (module),
  252. "__DATA", "__mod_term_func"))
  253. {
  254. flags |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED;
  255. }
  256. #if defined __ppc__
  257. flags |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES;
  258. #endif
  259. if (!NSUnLinkModule (module, flags))
  260. {
  261. DYLD__SETERROR (CANNOT_CLOSE);
  262. ++errors;
  263. }
  264. }
  265. }
  266. return errors;
  267. }
  268. /* A function called through the vtable to get the address of
  269. a symbol loaded from a particular module. */
  270. static void *
  271. vm_sym (lt_user_data loader_data, lt_module module, const char *name)
  272. {
  273. NSSymbol *nssym = 0;
  274. const mach_header *mh = (const mach_header *) module;
  275. char saveError[256] = "Symbol not found";
  276. if (module == (lt_module) -1)
  277. {
  278. void *address, *unused;
  279. _dyld_lookup_and_bind (name, (unsigned long*) &address, &unused);
  280. return address;
  281. }
  282. if (mh->magic == LT__MAGIC)
  283. {
  284. if (lt__image_symbol_p && lt__image_symbol)
  285. {
  286. if (lt__image_symbol_p (mh, name))
  287. {
  288. nssym = lt__image_symbol (mh, name, LT__SYMLOOKUP_OPTS);
  289. }
  290. }
  291. }
  292. else
  293. {
  294. nssym = NSLookupSymbolInModule (module, name);
  295. }
  296. if (!nssym)
  297. {
  298. strlcpy (saveError, dylderror (LT__STRERROR (SYMBOL_NOT_FOUND)), 255);
  299. saveError[255] = 0;
  300. if (!mh)
  301. {
  302. mh = (mach_header *)lt__nsmodule_get_header (module);
  303. }
  304. nssym = lt__linkedlib_symbol (name, mh);
  305. }
  306. if (!nssym)
  307. {
  308. LT__SETERRORSTR (saveError);
  309. }
  310. return nssym ? NSAddressOfSymbol (nssym) : 0;
  311. }
  312. /* --- HELPER FUNCTIONS --- */
  313. /* Return the dyld error string, or the passed in error string if none. */
  314. static const char *
  315. dylderror (const char *errmsg)
  316. {
  317. NSLinkEditErrors ler;
  318. int lerno;
  319. const char *file;
  320. const char *errstr;
  321. NSLinkEditError (&ler, &lerno, &file, &errstr);
  322. if (! (errstr && *errstr))
  323. {
  324. errstr = errmsg;
  325. }
  326. return errstr;
  327. }
  328. /* There should probably be an apple dyld api for this. */
  329. static const mach_header *
  330. lt__nsmodule_get_header (NSModule module)
  331. {
  332. int i = _dyld_image_count();
  333. const char *modname = NSNameOfModule (module);
  334. const mach_header *mh = 0;
  335. if (!modname)
  336. return NULL;
  337. while (i > 0)
  338. {
  339. --i;
  340. if (strneq (_dyld_get_image_name (i), modname))
  341. {
  342. mh = _dyld_get_image_header (i);
  343. break;
  344. }
  345. }
  346. return mh;
  347. }
  348. /* NSAddImage is also used to get the loaded image, but it only works if
  349. the lib is installed, for uninstalled libs we need to check the
  350. install_names against each other. Note that this is still broken if
  351. DYLD_IMAGE_SUFFIX is set and a different lib was loaded as a result. */
  352. static const char *
  353. lt__header_get_instnam (const mach_header *mh)
  354. {
  355. unsigned long offset = sizeof(mach_header);
  356. const char* result = 0;
  357. int j;
  358. for (j = 0; j < mh->ncmds; j++)
  359. {
  360. struct load_command *lc;
  361. lc = (struct load_command*) (((unsigned long) mh) + offset);
  362. if (LC_ID_DYLIB == lc->cmd)
  363. {
  364. result=(char*)(((dylib_command*) lc)->dylib.name.offset +
  365. (unsigned long) lc);
  366. }
  367. offset += lc->cmdsize;
  368. }
  369. return result;
  370. }
  371. static const mach_header *
  372. lt__match_loadedlib (const char *name)
  373. {
  374. const mach_header *mh = 0;
  375. int i = _dyld_image_count();
  376. while (i > 0)
  377. {
  378. const char *id;
  379. --i;
  380. id = lt__header_get_instnam (_dyld_get_image_header (i));
  381. if (id && strneq (id, name))
  382. {
  383. mh = _dyld_get_image_header (i);
  384. break;
  385. }
  386. }
  387. return mh;
  388. }
  389. /* Safe to assume our mh is good. */
  390. static NSSymbol
  391. lt__linkedlib_symbol (const char *symname, const mach_header *mh)
  392. {
  393. NSSymbol symbol = 0;
  394. if (lt__image_symbol && NSIsSymbolNameDefined (symname))
  395. {
  396. unsigned long offset = sizeof(mach_header);
  397. struct load_command *lc;
  398. int j;
  399. for (j = 0; j < mh->ncmds; j++)
  400. {
  401. lc = (struct load_command*) (((unsigned long) mh) + offset);
  402. if ((LC_LOAD_DYLIB == lc->cmd) || (LC_LOAD_WEAK_DYLIB == lc->cmd))
  403. {
  404. unsigned long base = ((dylib_command *) lc)->dylib.name.offset;
  405. char *name = (char *) (base + (unsigned long) lc);
  406. const mach_header *mh1 = lt__match_loadedlib (name);
  407. if (!mh1)
  408. {
  409. /* Maybe NSAddImage can find it */
  410. mh1 = lt__addimage (name,
  411. NSADDIMAGE_OPTION_RETURN_ONLY_IF_LOADED
  412. | NSADDIMAGE_OPTION_WITH_SEARCHING
  413. | NSADDIMAGE_OPTION_RETURN_ON_ERROR);
  414. }
  415. if (mh1)
  416. {
  417. symbol = lt__image_symbol (mh1, symname, LT__SYMLOOKUP_OPTS);
  418. if (symbol)
  419. break;
  420. }
  421. }
  422. offset += lc->cmdsize;
  423. }
  424. }
  425. return symbol;
  426. }