From c25b9e2337aad02073a199619f6f754f15cccd38 Mon Sep 17 00:00:00 2001 From: comex Date: Mon, 19 Jan 2015 19:12:32 -0500 Subject: more reorganization - move OS X/iOS specific stuff into its own directory --- lib/interpose.c | 224 -------------------------------------------------------- 1 file changed, 224 deletions(-) delete mode 100644 lib/interpose.c (limited to 'lib/interpose.c') diff --git a/lib/interpose.c b/lib/interpose.c deleted file mode 100644 index 06a357f..0000000 --- a/lib/interpose.c +++ /dev/null @@ -1,224 +0,0 @@ -#ifdef __APPLE__ - -#include -#include - -#include "substitute.h" -#include "substitute-internal.h" - -struct interpose_state { - size_t nsegments; - segment_command_x **segments; - size_t max_segments; - uintptr_t slide; - const struct substitute_import_hook *hooks; - size_t nhooks; - segment_command_x *stack_segments[32]; -}; - -static uintptr_t read_leb128(void **ptr, void *end, bool is_signed) { - uintptr_t result = 0; - uint8_t *p = *ptr; - uint8_t bit; - unsigned int shift = 0; - do { - if (p >= (uint8_t *) end) - return 0; - bit = *p++; - uintptr_t k = bit & 0x7f; - if (shift < sizeof(uintptr_t) * 8) - result |= k << shift; - shift += 7; - } while (bit & 0x80); - if (is_signed && (bit & 0x40)) - result |= ~((uintptr_t) 0) << shift; - *ptr = p; - return result; -} - -static inline char *read_cstring(void **ptr, void *end) { - char *s = *ptr; - *ptr = s + strnlen(s, (char *) end - s); - return s; -} - -static int try_bind_section(void *bind, size_t size, const struct interpose_state *st, - bool lazy) { - void *ptr = bind, *end = bind + size; - const char *sym = NULL; - uint8_t type = lazy ? BIND_TYPE_POINTER : 0; - intptr_t addend = 0; - size_t offset = 0; - void *segment = NULL; - while (ptr < end) { - uint8_t byte = *(uint8_t *) ptr; - ptr++; - uint8_t immediate = byte & BIND_IMMEDIATE_MASK; - uint8_t opcode = byte & BIND_OPCODE_MASK; - - uintptr_t count, stride; - - switch(opcode) { - case BIND_OPCODE_DONE: - case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: - case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: - break; - case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: - read_leb128(&ptr, end, false); - break; - case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: - sym = read_cstring(&ptr, end); - /* ignoring flags for now */ - break; - case BIND_OPCODE_SET_TYPE_IMM: - type = immediate; - break; - case BIND_OPCODE_SET_ADDEND_SLEB: - addend = read_leb128(&ptr, end, true); - break; - case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: - if (immediate < st->nsegments) - segment = (void *) (st->segments[immediate]->vmaddr + st->slide); - offset = read_leb128(&ptr, end, false); - break; - case BIND_OPCODE_ADD_ADDR_ULEB: - offset += read_leb128(&ptr, end, false); - break; - case BIND_OPCODE_DO_BIND: - count = 1; - stride = sizeof(void *); - goto bind; - case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: - count = 1; - stride = read_leb128(&ptr, end, false) + sizeof(void *); - goto bind; - case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: - count = 1; - stride = immediate * sizeof(void *) + sizeof(void *); - goto bind; - case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: - count = read_leb128(&ptr, end, false); - stride = read_leb128(&ptr, end, false) + sizeof(void *); - goto bind; - bind: - if (segment && sym) { - const struct substitute_import_hook *h; - size_t i; - for (i = 0; i < st->nhooks; i++) { - h = &st->hooks[i]; - if (!strcmp(sym, h->name)) - break; - } - if (i != st->nhooks) { - while (count--) { - uintptr_t new = (uintptr_t) h->replacement + addend; - uintptr_t old; - void *p = (void *) (segment + offset); - switch (type) { - case BIND_TYPE_POINTER: { - old = __atomic_exchange_n((uintptr_t *) p, new, __ATOMIC_RELAXED); - break; - } - case BIND_TYPE_TEXT_ABSOLUTE32: { - if ((uint32_t) new != new) { - /* text rels should only show up on i386, where - * this is impossible... */ - panic("bad TEXT_ABSOLUTE32 rel\n"); - } - old = __atomic_exchange_n((uint32_t *) p, (uint32_t) new, __ATOMIC_RELAXED); - break; - } - case BIND_TYPE_TEXT_PCREL32: { - uintptr_t pc = (uintptr_t) p + 4; - uintptr_t rel = new - pc; - if ((uint32_t) rel != rel) { - /* ditto */ - panic("bad TEXT_ABSOLUTE32 rel\n"); - } - old = __atomic_exchange_n((uint32_t *) p, (uint32_t) rel, __ATOMIC_RELAXED); - old += pc; - break; - } - default: - panic("unknown relocation type\n"); - break; - } - if (h->old_ptr) - *(uintptr_t *) h->old_ptr = old - addend; - } - break; - } - } - offset += count * stride; - break; - } - } - return SUBSTITUTE_OK; -} - -static void *off_to_addr(const struct interpose_state *st, uint32_t off) { - for (size_t i = 0; i < st->nsegments; i++) { - const segment_command_x *sc = st->segments[i]; - if ((off - sc->fileoff) < sc->filesize) - return (void *) (sc->vmaddr + st->slide + off - sc->fileoff); - } - return NULL; -} - -EXPORT -int substitute_interpose_imports(const struct substitute_image *image, - const struct substitute_import_hook *hooks, - size_t nhooks, int options) { - int ret = SUBSTITUTE_OK; - - if (options != 0) - panic("%s: unrecognized options\n", __func__); - - struct interpose_state st; - st.slide = image->slide; - st.nsegments = 0; - st.hooks = hooks; - st.nhooks = nhooks; - st.segments = st.stack_segments; - st.max_segments = sizeof(st.stack_segments) / sizeof(*st.stack_segments); - - const mach_header_x *mh = image->image_header; - const struct load_command *lc = (void *) (mh + 1); - for (uint32_t i = 0; i < mh->ncmds; i++) { - if (lc->cmd == LC_SEGMENT_X) { - segment_command_x *sc = (void *) lc; - if (st.nsegments == st.max_segments) { - segment_command_x **new = calloc(st.nsegments * 2, sizeof(*st.segments)); - if (!new) - substitute_panic("%s: out of memory\n", __func__); - memcpy(new, st.segments, st.nsegments * sizeof(*st.segments)); - if (st.segments != st.stack_segments) - free(st.segments); - st.segments = new; - } - st.segments[st.nsegments++] = sc; - } - lc = (void *) lc + lc->cmdsize; - } - - lc = (void *) (mh + 1); - for (uint32_t i = 0; i < mh->ncmds; i++) { - if (lc->cmd == LC_DYLD_INFO || lc->cmd == LC_DYLD_INFO_ONLY) { - struct dyld_info_command *dc = (void *) lc; - int ret; - if ((ret = try_bind_section(off_to_addr(&st, dc->bind_off), dc->bind_size, &st, false)) || - (ret = try_bind_section(off_to_addr(&st, dc->weak_bind_off), dc->weak_bind_size, &st, false)) || - (ret = try_bind_section(off_to_addr(&st, dc->lazy_bind_off), dc->lazy_bind_size, &st, true))) - goto fail; - - break; - } - lc = (void *) lc + lc->cmdsize; - } -fail: - if (st.segments != st.stack_segments) - free(st.segments); - return ret; -} - -#endif /* __APPLE__ */ -- cgit v1.2.3