static char* process_dynamic_segment (char *base, Elf_Phdr *dyn_phdr, SCM *init_out, SCM *entry_out, char **frame_maps_out) { char *dyn_addr = base + dyn_phdr->p_vaddr; Elf_Dyn *dyn = (Elf_Dyn *) dyn_addr; size_t i, dyn_size = dyn_phdr->p_memsz / sizeof (Elf_Dyn); char *init = 0, *gc_root = 0, *entry = 0, *frame_maps = 0; scm_t_ptrdiff gc_root_size = 0; enum bytecode_kind bytecode_kind = BYTECODE_KIND_NONE; for (i = 0; i < dyn_size; i++) { if (dyn[i].d_tag == DT_NULL) break; switch (dyn[i].d_tag) { case DT_INIT: if (init) return "duplicate DT_INIT"; init = base + dyn[i].d_un.d_val; break; case DT_GUILE_GC_ROOT: if (gc_root) return "duplicate DT_GUILE_GC_ROOT"; gc_root = base + dyn[i].d_un.d_val; break; case DT_GUILE_GC_ROOT_SZ: if (gc_root_size) return "duplicate DT_GUILE_GC_ROOT_SZ"; gc_root_size = dyn[i].d_un.d_val; break; case DT_GUILE_ENTRY: if (entry) return "duplicate DT_GUILE_ENTRY"; entry = base + dyn[i].d_un.d_val; break; case DT_GUILE_VM_VERSION: if (bytecode_kind != BYTECODE_KIND_NONE) return "duplicate DT_GUILE_VM_VERSION"; { scm_t_uint16 major = dyn[i].d_un.d_val >> 16; scm_t_uint16 minor = dyn[i].d_un.d_val & 0xffff; switch (major) { case 0x0202: bytecode_kind = BYTECODE_KIND_GUILE_2_2; /* As we get closer to 2.2, we will allow for backwards compatibility and we can change this test to ">" instead of "!=". However until then, to deal with VM churn it's best to keep these things in lock-step. */ if (minor != SCM_OBJCODE_MINOR_VERSION) return "incompatible bytecode version"; break; default: return "incompatible bytecode kind"; } break; } case DT_GUILE_FRAME_MAPS: if (frame_maps) return "duplicate DT_GUILE_FRAME_MAPS"; frame_maps = base + dyn[i].d_un.d_val; break; } } if (!entry) return "missing DT_GUILE_ENTRY"; switch (bytecode_kind) { case BYTECODE_KIND_GUILE_2_2: if ((scm_t_uintptr) init % 4) return "unaligned DT_INIT"; if ((scm_t_uintptr) entry % 4) return "unaligned DT_GUILE_ENTRY"; break; case BYTECODE_KIND_NONE: default: return "missing DT_GUILE_VM_VERSION"; } if (gc_root) GC_add_roots (gc_root, gc_root + gc_root_size); *init_out = init ? pointer_to_procedure (bytecode_kind, init) : SCM_BOOL_F; *entry_out = pointer_to_procedure (bytecode_kind, entry); *frame_maps_out = frame_maps; return NULL; }
static char* process_dynamic_segment (char *base, Elf_Phdr *dyn_phdr, SCM *init_out, SCM *entry_out) { char *dyn_addr = base + dyn_phdr->p_vaddr; Elf_Dyn *dyn = (Elf_Dyn *) dyn_addr; size_t i, dyn_size = dyn_phdr->p_memsz / sizeof (Elf_Dyn); char *init = 0, *gc_root = 0, *entry = 0; scm_t_ptrdiff gc_root_size = 0; enum bytecode_kind bytecode_kind = BYTECODE_KIND_NONE; for (i = 0; i < dyn_size; i++) { if (dyn[i].d_tag == DT_NULL) break; switch (dyn[i].d_tag) { case DT_INIT: if (init) return "duplicate DT_INIT"; init = base + dyn[i].d_un.d_val; break; case DT_GUILE_GC_ROOT: if (gc_root) return "duplicate DT_GUILE_GC_ROOT"; gc_root = base + dyn[i].d_un.d_val; break; case DT_GUILE_GC_ROOT_SZ: if (gc_root_size) return "duplicate DT_GUILE_GC_ROOT_SZ"; gc_root_size = dyn[i].d_un.d_val; break; case DT_GUILE_ENTRY: if (entry) return "duplicate DT_GUILE_ENTRY"; entry = base + dyn[i].d_un.d_val; break; case DT_GUILE_RTL_VERSION: if (bytecode_kind != BYTECODE_KIND_NONE) return "duplicate DT_GUILE_RTL_VERSION"; { scm_t_uint16 major = dyn[i].d_un.d_val >> 16; scm_t_uint16 minor = dyn[i].d_un.d_val & 0xffff; if (major != 0x0200) return "incompatible bytecode kind"; if (minor > SCM_OBJCODE_MINOR_VERSION) return "incompatible bytecode version"; bytecode_kind = BYTECODE_KIND_GUILE_2_0; break; } } } if (bytecode_kind != BYTECODE_KIND_GUILE_2_0) return "missing DT_GUILE_RTL_VERSION"; if (init) return "unexpected DT_INIT"; if ((scm_t_uintptr) entry % 8) return "unaligned DT_GUILE_ENTRY"; if (!entry) return "missing DT_GUILE_ENTRY"; if (gc_root) GC_add_roots (gc_root, gc_root + gc_root_size); *init_out = SCM_BOOL_F; *entry_out = pointer_to_procedure (bytecode_kind, entry); return NULL; }