objcodes.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. /* Copyright (C) 2001, 2009, 2010, 2011, 2012
  2. * 2013 Free Software Foundation, Inc.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public License
  6. * as published by the Free Software Foundation; either version 3 of
  7. * the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301 USA
  18. */
  19. #if HAVE_CONFIG_H
  20. # include <config.h>
  21. #endif
  22. #include <string.h>
  23. #include <fcntl.h>
  24. #include <unistd.h>
  25. #ifdef HAVE_SYS_MMAN_H
  26. #include <sys/mman.h>
  27. #endif
  28. #include <sys/stat.h>
  29. #include <sys/types.h>
  30. #include <assert.h>
  31. #include <alignof.h>
  32. #include <byteswap.h>
  33. #include <full-read.h>
  34. #include "_scm.h"
  35. #include "elf.h"
  36. #include "programs.h"
  37. #include "objcodes.h"
  38. /* Before, we used __BYTE_ORDER, but that is not defined on all
  39. systems. So punt and use automake, PDP endianness be damned. */
  40. #define SCM_BYTE_ORDER_BE 4321
  41. #define SCM_BYTE_ORDER_LE 1234
  42. /* Byte order of the build machine. */
  43. #ifdef WORDS_BIGENDIAN
  44. #define SCM_BYTE_ORDER SCM_BYTE_ORDER_BE
  45. #else
  46. #define SCM_BYTE_ORDER SCM_BYTE_ORDER_LE
  47. #endif
  48. /* This file contains the loader for Guile's on-disk format: ELF with
  49. some custom tags in the dynamic segment. */
  50. #if SIZEOF_SCM_T_BITS == 4
  51. #define Elf_Half Elf32_Half
  52. #define Elf_Word Elf32_Word
  53. #define Elf_Ehdr Elf32_Ehdr
  54. #define ELFCLASS ELFCLASS32
  55. #define Elf_Phdr Elf32_Phdr
  56. #define Elf_Dyn Elf32_Dyn
  57. #elif SIZEOF_SCM_T_BITS == 8
  58. #define Elf_Half Elf64_Half
  59. #define Elf_Word Elf64_Word
  60. #define Elf_Ehdr Elf64_Ehdr
  61. #define ELFCLASS ELFCLASS64
  62. #define Elf_Phdr Elf64_Phdr
  63. #define Elf_Dyn Elf64_Dyn
  64. #else
  65. #error
  66. #endif
  67. #define DT_LOGUILE 0x37146000 /* Start of Guile-specific */
  68. #define DT_GUILE_GC_ROOT 0x37146000 /* Offset of GC roots */
  69. #define DT_GUILE_GC_ROOT_SZ 0x37146001 /* Size in machine words of GC
  70. roots */
  71. #define DT_GUILE_ENTRY 0x37146002 /* Address of entry thunk */
  72. #define DT_GUILE_RTL_VERSION 0x37146003 /* Bytecode version */
  73. #define DT_HIGUILE 0x37146fff /* End of Guile-specific */
  74. #ifdef WORDS_BIGENDIAN
  75. #define ELFDATA ELFDATA2MSB
  76. #else
  77. #define ELFDATA ELFDATA2LSB
  78. #endif
  79. static void register_elf (char *data, size_t len);
  80. enum bytecode_kind
  81. {
  82. BYTECODE_KIND_NONE,
  83. BYTECODE_KIND_GUILE_2_0,
  84. BYTECODE_KIND_GUILE_2_2
  85. };
  86. static SCM
  87. pointer_to_procedure (enum bytecode_kind bytecode_kind, char *ptr)
  88. {
  89. switch (bytecode_kind)
  90. {
  91. case BYTECODE_KIND_GUILE_2_0:
  92. {
  93. SCM objcode;
  94. scm_t_bits tag = SCM_MAKE_OBJCODE_TAG (SCM_OBJCODE_TYPE_MMAP, 0);
  95. objcode = scm_double_cell (tag, (scm_t_bits) ptr, SCM_BOOL_F_BITS, 0);
  96. return scm_make_program (objcode, SCM_BOOL_F, SCM_UNDEFINED);
  97. }
  98. case BYTECODE_KIND_GUILE_2_2:
  99. {
  100. return scm_i_make_rtl_program ((scm_t_uint32 *) ptr);
  101. }
  102. case BYTECODE_KIND_NONE:
  103. default:
  104. abort ();
  105. }
  106. }
  107. static const char*
  108. check_elf_header (const Elf_Ehdr *header)
  109. {
  110. if (!(header->e_ident[EI_MAG0] == ELFMAG0
  111. && header->e_ident[EI_MAG1] == ELFMAG1
  112. && header->e_ident[EI_MAG2] == ELFMAG2
  113. && header->e_ident[EI_MAG3] == ELFMAG3))
  114. return "not an ELF file";
  115. if (header->e_ident[EI_CLASS] != ELFCLASS)
  116. return "ELF file does not have native word size";
  117. if (header->e_ident[EI_DATA] != ELFDATA)
  118. return "ELF file does not have native byte order";
  119. if (header->e_ident[EI_VERSION] != EV_CURRENT)
  120. return "bad ELF version";
  121. if (header->e_ident[EI_OSABI] != ELFOSABI_STANDALONE)
  122. return "unexpected OS ABI";
  123. if (header->e_ident[EI_ABIVERSION] != 0)
  124. return "unexpected ABI version";
  125. if (header->e_type != ET_DYN)
  126. return "unexpected ELF type";
  127. if (header->e_machine != EM_NONE)
  128. return "unexpected machine";
  129. if (header->e_version != EV_CURRENT)
  130. return "unexpected ELF version";
  131. if (header->e_ehsize != sizeof *header)
  132. return "unexpected header size";
  133. if (header->e_phentsize != sizeof (Elf_Phdr))
  134. return "unexpected program header size";
  135. return NULL;
  136. }
  137. #define IS_ALIGNED(offset, alignment) \
  138. (!((offset) & ((alignment) - 1)))
  139. #define ALIGN(offset, alignment) \
  140. ((offset + (alignment - 1)) & ~(alignment - 1))
  141. /* Return the alignment required by the ELF at DATA, of LEN bytes. */
  142. static size_t
  143. elf_alignment (const char *data, size_t len)
  144. {
  145. Elf_Ehdr *header;
  146. int i;
  147. size_t alignment = 8;
  148. if (len < sizeof(Elf_Ehdr))
  149. return alignment;
  150. header = (Elf_Ehdr *) data;
  151. if (header->e_phoff + header->e_phnum * header->e_phentsize >= len)
  152. return alignment;
  153. for (i = 0; i < header->e_phnum; i++)
  154. {
  155. Elf_Phdr *phdr;
  156. const char *phdr_addr = data + header->e_phoff + i * header->e_phentsize;
  157. if (!IS_ALIGNED ((scm_t_uintptr) phdr_addr, alignof_type (Elf_Phdr)))
  158. return alignment;
  159. phdr = (Elf_Phdr *) phdr_addr;
  160. if (phdr->p_align & (phdr->p_align - 1))
  161. return alignment;
  162. if (phdr->p_align > alignment)
  163. alignment = phdr->p_align;
  164. }
  165. return alignment;
  166. }
  167. /* This function leaks the memory that it allocates. */
  168. static char*
  169. alloc_aligned (size_t len, unsigned alignment)
  170. {
  171. char *ret;
  172. if (alignment == 8)
  173. {
  174. /* FIXME: Assert that we actually have an 8-byte-aligned malloc. */
  175. ret = malloc (len);
  176. }
  177. #if defined(HAVE_SYS_MMAN_H) && defined(MMAP_ANONYMOUS)
  178. else if (alignment == SCM_PAGE_SIZE)
  179. {
  180. ret = mmap (NULL, len, PROT_READ | PROT_WRITE, -1, 0);
  181. if (ret == MAP_FAILED)
  182. SCM_SYSERROR;
  183. }
  184. #endif
  185. else
  186. {
  187. if (len + alignment < len)
  188. abort ();
  189. ret = malloc (len + alignment - 1);
  190. if (!ret)
  191. abort ();
  192. ret = (char *) ALIGN ((scm_t_uintptr) ret, alignment);
  193. }
  194. return ret;
  195. }
  196. static char*
  197. copy_and_align_elf_data (const char *data, size_t len)
  198. {
  199. size_t alignment;
  200. char *copy;
  201. alignment = elf_alignment (data, len);
  202. copy = alloc_aligned (len, alignment);
  203. memcpy(copy, data, len);
  204. return copy;
  205. }
  206. #ifdef HAVE_SYS_MMAN_H
  207. static int
  208. segment_flags_to_prot (Elf_Word flags)
  209. {
  210. int prot = 0;
  211. if (flags & PF_X)
  212. prot |= PROT_EXEC;
  213. if (flags & PF_W)
  214. prot |= PROT_WRITE;
  215. if (flags & PF_R)
  216. prot |= PROT_READ;
  217. return prot;
  218. }
  219. #endif
  220. static char*
  221. process_dynamic_segment (char *base, Elf_Phdr *dyn_phdr,
  222. SCM *init_out, SCM *entry_out)
  223. {
  224. char *dyn_addr = base + dyn_phdr->p_vaddr;
  225. Elf_Dyn *dyn = (Elf_Dyn *) dyn_addr;
  226. size_t i, dyn_size = dyn_phdr->p_memsz / sizeof (Elf_Dyn);
  227. char *init = 0, *gc_root = 0, *entry = 0;
  228. scm_t_ptrdiff gc_root_size = 0;
  229. enum bytecode_kind bytecode_kind = BYTECODE_KIND_NONE;
  230. for (i = 0; i < dyn_size; i++)
  231. {
  232. if (dyn[i].d_tag == DT_NULL)
  233. break;
  234. switch (dyn[i].d_tag)
  235. {
  236. case DT_INIT:
  237. if (init)
  238. return "duplicate DT_INIT";
  239. init = base + dyn[i].d_un.d_val;
  240. break;
  241. case DT_GUILE_GC_ROOT:
  242. if (gc_root)
  243. return "duplicate DT_GUILE_GC_ROOT";
  244. gc_root = base + dyn[i].d_un.d_val;
  245. break;
  246. case DT_GUILE_GC_ROOT_SZ:
  247. if (gc_root_size)
  248. return "duplicate DT_GUILE_GC_ROOT_SZ";
  249. gc_root_size = dyn[i].d_un.d_val;
  250. break;
  251. case DT_GUILE_ENTRY:
  252. if (entry)
  253. return "duplicate DT_GUILE_ENTRY";
  254. entry = base + dyn[i].d_un.d_val;
  255. break;
  256. case DT_GUILE_RTL_VERSION:
  257. if (bytecode_kind != BYTECODE_KIND_NONE)
  258. return "duplicate DT_GUILE_RTL_VERSION";
  259. {
  260. scm_t_uint16 major = dyn[i].d_un.d_val >> 16;
  261. scm_t_uint16 minor = dyn[i].d_un.d_val & 0xffff;
  262. switch (major)
  263. {
  264. case 0x0200:
  265. bytecode_kind = BYTECODE_KIND_GUILE_2_0;
  266. if (minor > SCM_OBJCODE_MINOR_VERSION)
  267. return "incompatible bytecode version";
  268. break;
  269. case 0x0202:
  270. bytecode_kind = BYTECODE_KIND_GUILE_2_2;
  271. if (minor)
  272. return "incompatible bytecode version";
  273. break;
  274. default:
  275. return "incompatible bytecode kind";
  276. }
  277. break;
  278. }
  279. }
  280. }
  281. if (!entry)
  282. return "missing DT_GUILE_ENTRY";
  283. switch (bytecode_kind)
  284. {
  285. case BYTECODE_KIND_GUILE_2_0:
  286. if (init)
  287. return "unexpected DT_INIT";
  288. if ((scm_t_uintptr) entry % 8)
  289. return "unaligned DT_GUILE_ENTRY";
  290. break;
  291. case BYTECODE_KIND_GUILE_2_2:
  292. if ((scm_t_uintptr) init % 4)
  293. return "unaligned DT_INIT";
  294. if ((scm_t_uintptr) entry % 4)
  295. return "unaligned DT_GUILE_ENTRY";
  296. break;
  297. case BYTECODE_KIND_NONE:
  298. default:
  299. return "missing DT_GUILE_RTL_VERSION";
  300. }
  301. if (gc_root)
  302. GC_add_roots (gc_root, gc_root + gc_root_size);
  303. *init_out = init ? pointer_to_procedure (bytecode_kind, init) : SCM_BOOL_F;
  304. *entry_out = pointer_to_procedure (bytecode_kind, entry);
  305. return NULL;
  306. }
  307. #define ABORT(msg) do { err_msg = msg; goto cleanup; } while (0)
  308. static SCM
  309. load_thunk_from_memory (char *data, size_t len, int is_read_only)
  310. #define FUNC_NAME "load-thunk-from-memory"
  311. {
  312. Elf_Ehdr *header;
  313. Elf_Phdr *ph;
  314. const char *err_msg = 0;
  315. size_t n, alignment = 8;
  316. int i;
  317. int dynamic_segment = -1;
  318. SCM init = SCM_BOOL_F, entry = SCM_BOOL_F;
  319. if (len < sizeof *header)
  320. ABORT ("object file too small");
  321. header = (Elf_Ehdr*) data;
  322. if ((err_msg = check_elf_header (header)))
  323. goto cleanup;
  324. if (header->e_phnum == 0)
  325. ABORT ("no loadable segments");
  326. n = header->e_phnum;
  327. if (len < header->e_phoff + n * sizeof (Elf_Phdr))
  328. ABORT ("object file too small");
  329. ph = (Elf_Phdr*) (data + header->e_phoff);
  330. /* Check that the segment table is sane. */
  331. for (i = 0; i < n; i++)
  332. {
  333. if (ph[i].p_filesz != ph[i].p_memsz)
  334. ABORT ("expected p_filesz == p_memsz");
  335. if (!ph[i].p_flags)
  336. ABORT ("expected nonzero segment flags");
  337. if (ph[i].p_align < alignment)
  338. {
  339. if (ph[i].p_align % alignment)
  340. ABORT ("expected new alignment to be multiple of old");
  341. alignment = ph[i].p_align;
  342. }
  343. if (ph[i].p_type == PT_DYNAMIC)
  344. {
  345. if (dynamic_segment >= 0)
  346. ABORT ("expected only one PT_DYNAMIC segment");
  347. dynamic_segment = i;
  348. }
  349. if (i == 0)
  350. {
  351. if (ph[i].p_vaddr != 0)
  352. ABORT ("first loadable vaddr is not 0");
  353. }
  354. else
  355. {
  356. if (ph[i].p_vaddr < ph[i-1].p_vaddr + ph[i-1].p_memsz)
  357. ABORT ("overlapping segments");
  358. if (ph[i].p_offset + ph[i].p_filesz > len)
  359. ABORT ("segment beyond end of byte array");
  360. }
  361. }
  362. if (dynamic_segment < 0)
  363. ABORT ("no PT_DYNAMIC segment");
  364. if (!IS_ALIGNED ((scm_t_uintptr) data, alignment))
  365. ABORT ("incorrectly aligned base");
  366. /* Allow writes to writable pages. */
  367. if (is_read_only)
  368. {
  369. #ifdef HAVE_SYS_MMAN_H
  370. for (i = 0; i < n; i++)
  371. {
  372. if (ph[i].p_flags == PF_R)
  373. continue;
  374. if (ph[i].p_align != 4096)
  375. continue;
  376. if (mprotect (data + ph[i].p_vaddr,
  377. ph[i].p_memsz,
  378. segment_flags_to_prot (ph[i].p_flags)))
  379. goto cleanup;
  380. }
  381. #else
  382. ABORT ("expected writable pages");
  383. #endif
  384. }
  385. if ((err_msg = process_dynamic_segment (data, &ph[dynamic_segment],
  386. &init, &entry)))
  387. goto cleanup;
  388. if (scm_is_true (init))
  389. scm_call_0 (init);
  390. register_elf (data, len);
  391. /* Finally! Return the thunk. */
  392. return entry;
  393. cleanup:
  394. {
  395. if (errno)
  396. SCM_SYSERROR;
  397. scm_misc_error (FUNC_NAME, err_msg ? err_msg : "error loading ELF file",
  398. SCM_EOL);
  399. }
  400. }
  401. #undef FUNC_NAME
  402. #define SCM_PAGE_SIZE 4096
  403. static char*
  404. map_file_contents (int fd, size_t len, int *is_read_only)
  405. #define FUNC_NAME "load-thunk-from-file"
  406. {
  407. char *data;
  408. #ifdef HAVE_SYS_MMAN_H
  409. data = mmap (NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
  410. if (data == MAP_FAILED)
  411. SCM_SYSERROR;
  412. *is_read_only = 1;
  413. #else
  414. if (lseek (fd, 0, SEEK_START) < 0)
  415. {
  416. int errno_save = errno;
  417. (void) close (fd);
  418. errno = errno_save;
  419. SCM_SYSERROR;
  420. }
  421. /* Given that we are using the read fallback, optimistically assume
  422. that the .go files were made with 8-byte alignment.
  423. alignment. */
  424. data = malloc (end);
  425. if (!data)
  426. {
  427. (void) close (fd);
  428. scm_misc_error (FUNC_NAME, "failed to allocate ~A bytes",
  429. scm_list_1 (scm_from_size_t (end)));
  430. }
  431. if (full_read (fd, data, end) != end)
  432. {
  433. int errno_save = errno;
  434. (void) close (fd);
  435. errno = errno_save;
  436. if (errno)
  437. SCM_SYSERROR;
  438. scm_misc_error (FUNC_NAME, "short read while loading objcode",
  439. SCM_EOL);
  440. }
  441. /* If our optimism failed, fall back. */
  442. {
  443. unsigned alignment = sniff_elf_alignment (data, end);
  444. if (alignment != 8)
  445. {
  446. char *copy = copy_and_align_elf_data (data, end, alignment);
  447. free (data);
  448. data = copy;
  449. }
  450. }
  451. *is_read_only = 0;
  452. #endif
  453. return data;
  454. }
  455. #undef FUNC_NAME
  456. SCM_DEFINE (scm_load_thunk_from_file, "load-thunk-from-file", 1, 0, 0,
  457. (SCM filename),
  458. "")
  459. #define FUNC_NAME s_scm_load_thunk_from_file
  460. {
  461. char *c_filename;
  462. int fd, is_read_only;
  463. off_t end;
  464. char *data;
  465. SCM_VALIDATE_STRING (1, filename);
  466. c_filename = scm_to_locale_string (filename);
  467. fd = open (c_filename, O_RDONLY | O_BINARY | O_CLOEXEC);
  468. free (c_filename);
  469. if (fd < 0) SCM_SYSERROR;
  470. end = lseek (fd, 0, SEEK_END);
  471. if (end < 0)
  472. SCM_SYSERROR;
  473. data = map_file_contents (fd, end, &is_read_only);
  474. (void) close (fd);
  475. return load_thunk_from_memory (data, end, is_read_only);
  476. }
  477. #undef FUNC_NAME
  478. SCM_DEFINE (scm_load_thunk_from_memory, "load-thunk-from-memory", 1, 0, 0,
  479. (SCM bv),
  480. "")
  481. #define FUNC_NAME s_scm_load_thunk_from_memory
  482. {
  483. char *data;
  484. size_t len;
  485. SCM_VALIDATE_BYTEVECTOR (1, bv);
  486. data = (char *) SCM_BYTEVECTOR_CONTENTS (bv);
  487. len = SCM_BYTEVECTOR_LENGTH (bv);
  488. /* Copy data in order to align it, to trace its GC roots and
  489. writable sections, and to keep it in memory. */
  490. data = copy_and_align_elf_data (data, len);
  491. return load_thunk_from_memory (data, len, 0);
  492. }
  493. #undef FUNC_NAME
  494. /*
  495. * Objcode type
  496. */
  497. /* Convert X, which is in byte order BYTE_ORDER, to its native
  498. representation. */
  499. static inline uint32_t
  500. to_native_order (uint32_t x, int byte_order)
  501. {
  502. if (byte_order == SCM_BYTE_ORDER)
  503. return x;
  504. else
  505. return bswap_32 (x);
  506. }
  507. SCM
  508. scm_c_make_objcode_slice (SCM parent, const scm_t_uint8 *ptr)
  509. #define FUNC_NAME "make-objcode-slice"
  510. {
  511. const struct scm_objcode *data, *parent_data;
  512. const scm_t_uint8 *parent_base;
  513. SCM_VALIDATE_OBJCODE (1, parent);
  514. parent_data = SCM_OBJCODE_DATA (parent);
  515. parent_base = SCM_C_OBJCODE_BASE (parent_data);
  516. if (ptr < parent_base
  517. || ptr >= (parent_base + parent_data->len + parent_data->metalen
  518. - sizeof (struct scm_objcode)))
  519. scm_misc_error
  520. (FUNC_NAME, "offset out of bounds (~a vs ~a + ~a + ~a)",
  521. scm_list_4 (scm_from_unsigned_integer ((scm_t_bits) ptr),
  522. scm_from_unsigned_integer ((scm_t_bits) parent_base),
  523. scm_from_uint32 (parent_data->len),
  524. scm_from_uint32 (parent_data->metalen)));
  525. /* Make sure bytecode for the objcode-meta is suitable aligned. Failing to
  526. do so leads to SIGBUS/SIGSEGV on some arches (e.g., SPARC). */
  527. assert ((((scm_t_bits) ptr) &
  528. (alignof_type (struct scm_objcode) - 1UL)) == 0);
  529. data = (struct scm_objcode*) ptr;
  530. assert (SCM_C_OBJCODE_BASE (data) + data->len + data->metalen
  531. <= parent_base + parent_data->len + parent_data->metalen);
  532. return scm_double_cell (SCM_MAKE_OBJCODE_TAG (SCM_OBJCODE_TYPE_SLICE, 0),
  533. (scm_t_bits)data, SCM_UNPACK (parent), 0);
  534. }
  535. #undef FUNC_NAME
  536. struct mapped_elf_image
  537. {
  538. char *start;
  539. char *end;
  540. };
  541. static struct mapped_elf_image *mapped_elf_images = NULL;
  542. static size_t mapped_elf_images_count = 0;
  543. static size_t mapped_elf_images_allocated = 0;
  544. static size_t
  545. find_mapped_elf_insertion_index (char *ptr)
  546. {
  547. /* "mapped_elf_images_count" must never be dereferenced. */
  548. size_t start = 0, end = mapped_elf_images_count;
  549. while (start < end)
  550. {
  551. size_t n = start + (end - start) / 2;
  552. if (ptr < mapped_elf_images[n].end)
  553. end = n;
  554. else
  555. start = n + 1;
  556. }
  557. return start;
  558. }
  559. static void
  560. register_elf (char *data, size_t len)
  561. {
  562. scm_i_pthread_mutex_lock (&scm_i_misc_mutex);
  563. {
  564. /* My kingdom for a generic growable sorted vector library. */
  565. if (mapped_elf_images_count == mapped_elf_images_allocated)
  566. {
  567. struct mapped_elf_image *prev;
  568. size_t n;
  569. if (mapped_elf_images_allocated)
  570. mapped_elf_images_allocated *= 2;
  571. else
  572. mapped_elf_images_allocated = 16;
  573. prev = mapped_elf_images;
  574. mapped_elf_images =
  575. scm_gc_malloc_pointerless (sizeof (*mapped_elf_images)
  576. * mapped_elf_images_allocated,
  577. "mapped elf images");
  578. for (n = 0; n < mapped_elf_images_count; n++)
  579. {
  580. mapped_elf_images[n].start = prev[n].start;
  581. mapped_elf_images[n].end = prev[n].end;
  582. }
  583. }
  584. {
  585. size_t end;
  586. size_t n = find_mapped_elf_insertion_index (data);
  587. for (end = mapped_elf_images_count; n < end; end--)
  588. {
  589. mapped_elf_images[end].start = mapped_elf_images[end - 1].start;
  590. mapped_elf_images[end].end = mapped_elf_images[end - 1].end;
  591. }
  592. mapped_elf_images_count++;
  593. mapped_elf_images[n].start = data;
  594. mapped_elf_images[n].end = data + len;
  595. }
  596. }
  597. scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
  598. }
  599. static SCM
  600. scm_find_mapped_elf_image (SCM ip)
  601. {
  602. char *ptr = (char *) scm_to_uintptr_t (ip);
  603. SCM result;
  604. scm_i_pthread_mutex_lock (&scm_i_misc_mutex);
  605. {
  606. size_t n = find_mapped_elf_insertion_index ((char *) ptr);
  607. if (n < mapped_elf_images_count
  608. && mapped_elf_images[n].start <= ptr
  609. && ptr < mapped_elf_images[n].end)
  610. {
  611. signed char *data = (signed char *) mapped_elf_images[n].start;
  612. size_t len = mapped_elf_images[n].end - mapped_elf_images[n].start;
  613. result = scm_c_take_gc_bytevector (data, len, SCM_BOOL_F);
  614. }
  615. else
  616. result = SCM_BOOL_F;
  617. }
  618. scm_i_pthread_mutex_unlock (&scm_i_misc_mutex);
  619. return result;
  620. }
  621. /*
  622. * Scheme interface
  623. */
  624. SCM_DEFINE (scm_objcode_p, "objcode?", 1, 0, 0,
  625. (SCM obj),
  626. "")
  627. #define FUNC_NAME s_scm_objcode_p
  628. {
  629. return scm_from_bool (SCM_OBJCODE_P (obj));
  630. }
  631. #undef FUNC_NAME
  632. SCM_DEFINE (scm_objcode_meta, "objcode-meta", 1, 0, 0,
  633. (SCM objcode),
  634. "")
  635. #define FUNC_NAME s_scm_objcode_meta
  636. {
  637. SCM_VALIDATE_OBJCODE (1, objcode);
  638. if (SCM_OBJCODE_META_LEN (objcode) == 0)
  639. return SCM_BOOL_F;
  640. else
  641. return scm_c_make_objcode_slice (objcode, (SCM_OBJCODE_BASE (objcode)
  642. + SCM_OBJCODE_LEN (objcode)));
  643. }
  644. #undef FUNC_NAME
  645. /* Wrap BYTECODE in objcode, interpreting its lengths according to
  646. BYTE_ORDER. */
  647. static SCM
  648. bytecode_to_objcode (SCM bytecode, int byte_order)
  649. #define FUNC_NAME "bytecode->objcode"
  650. {
  651. size_t size, len, metalen;
  652. const scm_t_uint8 *c_bytecode;
  653. struct scm_objcode *data;
  654. if (!scm_is_bytevector (bytecode))
  655. scm_wrong_type_arg (FUNC_NAME, 1, bytecode);
  656. size = SCM_BYTEVECTOR_LENGTH (bytecode);
  657. c_bytecode = (const scm_t_uint8*)SCM_BYTEVECTOR_CONTENTS (bytecode);
  658. SCM_ASSERT_RANGE (0, bytecode, size >= sizeof(struct scm_objcode));
  659. data = (struct scm_objcode*)c_bytecode;
  660. len = to_native_order (data->len, byte_order);
  661. metalen = to_native_order (data->metalen, byte_order);
  662. if (len + metalen != (size - sizeof (*data)))
  663. scm_misc_error (FUNC_NAME, "bad bytevector size (~a != ~a)",
  664. scm_list_2 (scm_from_size_t (size),
  665. scm_from_uint32 (sizeof (*data) + len + metalen)));
  666. /* foolishly, we assume that as long as bytecode is around, that c_bytecode
  667. will be of the same length; perhaps a bad assumption? */
  668. return scm_double_cell (SCM_MAKE_OBJCODE_TAG (SCM_OBJCODE_TYPE_BYTEVECTOR, 0),
  669. (scm_t_bits)data, SCM_UNPACK (bytecode), 0);
  670. }
  671. #undef FUNC_NAME
  672. SCM_DEFINE (scm_bytecode_to_objcode, "bytecode->objcode", 1, 1, 0,
  673. (SCM bytecode, SCM endianness),
  674. "")
  675. #define FUNC_NAME s_scm_bytecode_to_objcode
  676. {
  677. int byte_order;
  678. if (SCM_UNBNDP (endianness))
  679. byte_order = SCM_BYTE_ORDER;
  680. else if (scm_is_eq (endianness, scm_endianness_big))
  681. byte_order = SCM_BYTE_ORDER_BE;
  682. else if (scm_is_eq (endianness, scm_endianness_little))
  683. byte_order = SCM_BYTE_ORDER_LE;
  684. else
  685. scm_wrong_type_arg (FUNC_NAME, 2, endianness);
  686. return bytecode_to_objcode (bytecode, byte_order);
  687. }
  688. #undef FUNC_NAME
  689. SCM_DEFINE (scm_objcode_to_bytecode, "objcode->bytecode", 1, 1, 0,
  690. (SCM objcode, SCM endianness),
  691. "")
  692. #define FUNC_NAME s_scm_objcode_to_bytecode
  693. {
  694. scm_t_uint32 len, meta_len, total_len;
  695. int byte_order;
  696. SCM_VALIDATE_OBJCODE (1, objcode);
  697. if (SCM_UNBNDP (endianness))
  698. byte_order = SCM_BYTE_ORDER;
  699. else if (scm_is_eq (endianness, scm_endianness_big))
  700. byte_order = SCM_BYTE_ORDER_BE;
  701. else if (scm_is_eq (endianness, scm_endianness_little))
  702. byte_order = SCM_BYTE_ORDER_LE;
  703. else
  704. scm_wrong_type_arg (FUNC_NAME, 2, endianness);
  705. len = SCM_OBJCODE_LEN (objcode);
  706. meta_len = SCM_OBJCODE_META_LEN (objcode);
  707. total_len = sizeof (struct scm_objcode);
  708. total_len += to_native_order (len, byte_order);
  709. total_len += to_native_order (meta_len, byte_order);
  710. return scm_c_take_gc_bytevector ((scm_t_int8*)SCM_OBJCODE_DATA (objcode),
  711. total_len, objcode);
  712. }
  713. #undef FUNC_NAME
  714. void
  715. scm_i_objcode_print (SCM objcode, SCM port, scm_print_state *pstate)
  716. {
  717. scm_puts_unlocked ("#<objcode ", port);
  718. scm_uintprint ((scm_t_bits)SCM_OBJCODE_BASE (objcode), 16, port);
  719. scm_puts_unlocked (">", port);
  720. }
  721. void
  722. scm_bootstrap_objcodes (void)
  723. {
  724. scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
  725. "scm_init_objcodes",
  726. (scm_t_extension_init_func)scm_init_objcodes, NULL);
  727. }
  728. void
  729. scm_init_objcodes (void)
  730. {
  731. #ifndef SCM_MAGIC_SNARFER
  732. #include "libguile/objcodes.x"
  733. #endif
  734. scm_c_define_gsubr ("find-mapped-elf-image", 1, 0, 0,
  735. (scm_t_subr) scm_find_mapped_elf_image);
  736. scm_c_define ("word-size", scm_from_size_t (sizeof(SCM)));
  737. scm_c_define ("byte-order", scm_from_uint16 (SCM_BYTE_ORDER));
  738. }
  739. /*
  740. Local Variables:
  741. c-file-style: "gnu"
  742. End:
  743. */