From c5d229e0ff193affde0caaddcfb3d26de0bb934f Mon Sep 17 00:00:00 2001 From: Michel Hidalgo Date: Tue, 7 Jul 2020 12:49:54 -0300 Subject: [PATCH 01/11] Fix regression in fc69876d2074af28d953dede6d633ba6a02c058f. Signed-off-by: Michel Hidalgo --- src/plt-elf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plt-elf.c b/src/plt-elf.c index ff20594..d2501aa 100644 --- a/src/plt-elf.c +++ b/src/plt-elf.c @@ -302,7 +302,7 @@ void plt_set_offsets(plt_offset *offset, size_t nb_off, plt_fn *newval) available on all unices. */ mmk_mprotect(page_start, 4096, PROT_READ|PROT_WRITE|PROT_EXEC); # if defined __clang__ // Check for Clang first, it may set __GNUC__ too. - __clear_cache(page_start, map + 4096); + __clear_cache(page_start, page_start + 4096); # elif defined __GNUC__ __builtin___clear_cache((char *)page_start, (char *)(page_start + 4096)); # endif From 87e9898ebc9f1644c00df74dc1b34bf20391661b Mon Sep 17 00:00:00 2001 From: Michel Hidalgo Date: Tue, 7 Jul 2020 13:03:26 -0300 Subject: [PATCH 02/11] Include vitals in trampoline implementation. Signed-off-by: Michel Hidalgo --- src/trampoline.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/trampoline.c b/src/trampoline.c index 17138b4..7456d9b 100644 --- a/src/trampoline.c +++ b/src/trampoline.c @@ -26,6 +26,8 @@ #include "mimick/assert.h" #include "trampoline.h" +#include "vitals.h" + #define PAGE_SIZE 0x1000 extern void mmk_trampoline(); From 03514a909d5f699e2bab827a8a9c51a78857b32a Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sun, 24 Jan 2021 21:10:49 +0000 Subject: [PATCH 03/11] Mac M1 build fix proposal. Darwin call conventions fixes. Unnecessary X bit on page creation since changed afterwards (otherwise crash on Darwin/ARM). --- CMakeLists.txt | 3 +++ src/asm/trampoline-aarch64.S | 11 +++++++---- src/trampoline.c | 9 ++++++--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a743ac..f15333e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,9 @@ else () else () message (FATAL_ERROR "Architecture '${_ARCH}' is not supported.") endif () + if (APPLE) + set (MMK_MANGLING "leading-underscore") + endif() set (ASM_EXTENSION ".S") endif () diff --git a/src/asm/trampoline-aarch64.S b/src/asm/trampoline-aarch64.S index c639be8..dc00aae 100644 --- a/src/asm/trampoline-aarch64.S +++ b/src/asm/trampoline-aarch64.S @@ -21,9 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include "mangling.h" -.globl mmk_trampoline -mmk_trampoline: +.align 8 +.globl MANGLE(mmk_trampoline) +MANGLE(mmk_trampoline): adr x16, . stp x7, x6, [sp, #-16]! @@ -70,6 +72,7 @@ ret_ctx: ldp x16, x30, [sp], #16 ret -.globl mmk_trampoline_end -mmk_trampoline_end: +.align 8 +.globl MANGLE(mmk_trampoline_end) +MANGLE(mmk_trampoline_end): nop diff --git a/src/trampoline.c b/src/trampoline.c index 7456d9b..1549b6d 100644 --- a/src/trampoline.c +++ b/src/trampoline.c @@ -53,13 +53,16 @@ plt_fn *create_trampoline(void *ctx, plt_fn *routine) mmk_assert(trampoline_sz < PAGE_SIZE); # if defined HAVE_MMAP_MAP_ANONYMOUS +# if !defined MAP_JIT +# define MAP_JIT 0 +# endif void **map = mmap(NULL, PAGE_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_JIT, -1, 0); # elif defined HAVE_MMAP_MAP_ANON void **map = mmap(NULL, PAGE_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); # else From f778baabe28ada5c723ce74d3ebe9492d9c9f389 Mon Sep 17 00:00:00 2001 From: Scott K Logan Date: Thu, 3 Dec 2020 14:28:32 -0800 Subject: [PATCH 04/11] Fix PLT_SEL_FILE for macOS and Linux The variable `name` contains everything after the `@`, which includes the `file:` prefix. The variable `val` should contain everything after the `file:` prefix, which should be appropriate for comparison with the library file name. --- src/plt-elf.c | 2 +- src/plt-mach-o.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plt-elf.c b/src/plt-elf.c index d2501aa..27f9ad2 100644 --- a/src/plt-elf.c +++ b/src/plt-elf.c @@ -196,7 +196,7 @@ plt_lib plt_get_lib(plt_ctx ctx, const char *name) } } else if (sel == PLT_SEL_NONE || sel == PLT_SEL_FILE) { const char *libname = get_lib_name(ctx, lm); - if (!strcmp(name, libname)) + if (!strcmp(val, libname)) return lm; } else if (sel == PLT_SEL_SYM) { if (get_offsets(ctx, lm, val, NULL) > 0) diff --git a/src/plt-mach-o.c b/src/plt-mach-o.c index e0b1d47..1292ddc 100644 --- a/src/plt-mach-o.c +++ b/src/plt-mach-o.c @@ -80,7 +80,7 @@ plt_lib plt_get_lib(plt_ctx ctx, const char *name) return i; } else if (sel == PLT_SEL_NONE || sel == PLT_SEL_FILE) { const char *img_name = _dyld_get_image_name(i); - if (img_name && !strcmp(img_name, name)) + if (img_name && !strcmp(img_name, val)) return i; } else if (sel == PLT_SEL_SYM) { plt_offset *off = plt_get_offsets(ctx, i, val, NULL); From 6a37161403a2cfccb94e9f1846cdb32776ca7d79 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Tue, 2 Mar 2021 18:27:54 +0000 Subject: [PATCH 05/11] Further Mac build fix proposal. mprotect symbol is needed too. also __clear_cache seems buggy on ARM64 thus calling directly related MacOS feature. --- src/trampoline.c | 8 ++++++-- src/vitals.c | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/trampoline.c b/src/trampoline.c index 1549b6d..5f74144 100644 --- a/src/trampoline.c +++ b/src/trampoline.c @@ -41,7 +41,9 @@ extern void mmk_trampoline_end(); # include # endif -# if defined __clang__ +# if defined __APPLE__ +# include // LLVM __clear_cache seems not working on Mac ARM64 +# elif defined __clang__ void __clear_cache(void *, void *); # endif @@ -83,7 +85,9 @@ plt_fn *create_trampoline(void *ctx, plt_fn *routine) *(map + 1) = (void *) routine; memcpy(map + 2, mmk_trampoline, trampoline_sz); mmk_assert(!mmk_mprotect(map, PAGE_SIZE, PROT_READ | PROT_EXEC)); -# if defined __clang__ // Check for Clang first, it may set __GNUC__ too. +# if defined __APPLE__ + sys_icache_invalidate(map, PAGE_SIZE); +# elif defined __clang__ // Check for Clang first, it may set __GNUC__ too. __clear_cache(map, map + PAGE_SIZE); # elif defined __GNUC__ __builtin___clear_cache((char *)map, (char *)(map + PAGE_SIZE)); diff --git a/src/vitals.c b/src/vitals.c index 0982d87..505f4eb 100644 --- a/src/vitals.c +++ b/src/vitals.c @@ -196,7 +196,7 @@ void mmk_init_vital_functions(plt_ctx ctx) INIT_VITAL_FUNC(malloc); INIT_VITAL_FUNC(realloc); INIT_VITAL_FUNC(free); -#ifdef MMK_EXE_FMT_ELF +#if defined(MMK_EXE_FMT_ELF) || defined(MMK_EXE_FMT_MACH_O) INIT_VITAL_FUNC(mprotect); #endif } From 9c0b9df5b6053178ddee063c087ec7d32adc1a07 Mon Sep 17 00:00:00 2001 From: Peter Edwards Date: Thu, 13 May 2021 23:47:48 +0100 Subject: [PATCH 06/11] Deal with archs that have DT_REL rather than DT_RELA This fixes the 32-bit travis tests - the code doesn't deal with the addend anyway. --- src/plt-elf.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/plt-elf.c b/src/plt-elf.c index 27f9ad2..e4cc10c 100644 --- a/src/plt-elf.c +++ b/src/plt-elf.c @@ -233,10 +233,24 @@ static size_t get_offsets(plt_ctx ctx, plt_lib lib, const char *name, plt_offset const char *strtab = (const char*) lib_dt_lookup(lib, DT_STRTAB); ElfW(Rel) *jmprel = lib_dt_lookup(lib, DT_JMPREL); - ElfW(Rel) *rel = lib_dt_lookup(lib, DT_RELA); - ElfWord rel_sz = lib_dt_lookup_val(lib, DT_RELASZ); + ElfWord jmprel_sz = lib_dt_lookup_val(lib, DT_PLTRELSZ); - ElfWord relent_sz = lib_dt_lookup_val(lib, DT_RELAENT); + ElfWord relent_sz; + ElfWord rel_sz; + + // For relocation sections try DT_RELA first, then DT_REL. We don't deal with + // addends anyway. + ElfW(Rel) *rel = lib_dt_lookup(lib, DT_RELA); + if (!rel) { + rel = lib_dt_lookup(lib, DT_REL); + if (!rel) + return 0; + rel_sz = lib_dt_lookup_val(lib, DT_RELSZ); + relent_sz = lib_dt_lookup_val(lib, DT_RELENT); + } else { + rel_sz = lib_dt_lookup_val(lib, DT_RELASZ); + relent_sz = lib_dt_lookup_val(lib, DT_RELAENT); + } if (!symtab || !strtab || !(rel || jmprel) || !(rel_sz || jmprel_sz) || !relent_sz) return 0; From 93b10bfe7f81d10fc9969062f498f64b1563346c Mon Sep 17 00:00:00 2001 From: Peter Edwards Date: Thu, 13 May 2021 19:01:42 +0100 Subject: [PATCH 07/11] Implement gnu_hash symbol lookup Use gnu_hash in preference to the standard hash table, as it's more efficient, and fall back to the tranditional table if we can't find it. This should fix problems on systems that do not provide the traditional ELF hash table for symbols. --- src/plt-elf.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/src/plt-elf.c b/src/plt-elf.c index e4cc10c..1562cab 100644 --- a/src/plt-elf.c +++ b/src/plt-elf.c @@ -363,15 +363,72 @@ static ElfW(Sym) *elf_hash_find(ElfW(Word) *hash, ElfW(Sym) *symtab, return NULL; } +struct gnu_hash_header { + uint32_t nbuckets; + uint32_t symoffset; + uint32_t bloom_size; + uint32_t bloom_shift; +}; + +static uint32_t gnu_hash(const char *s) +{ + const uint8_t *name = (const uint8_t *)s; + uint32_t h = 5381; + while (*name) + h = (h << 5) + h + *name++; + return h; +} + +static ElfW(Sym) *gnu_hash_find(struct gnu_hash_header *gnuhash, ElfW(Sym) *symtab, + const char *strtab, const char *name) +{ + ElfW(Off) *bloom = (ElfW(Off) *)(gnuhash + 1); + uint32_t *buckets = (uint32_t *)(bloom + gnuhash->bloom_size); + uint32_t *chains = buckets + gnuhash->nbuckets; + + uint32_t symhash = gnu_hash(name); + + // Grab the bloom filter entry, and test both h1 and h2 are present. + ElfW(Off) filter = bloom[(symhash / MMK_BITS) % gnuhash->bloom_size]; + if ((filter & (1UL << symhash % MMK_BITS)) == 0) + return NULL; + if ((filter & (1UL << (symhash >> gnuhash->bloom_shift) % MMK_BITS)) == 0) + return NULL; + + for (uint32_t idx = buckets[symhash % gnuhash->nbuckets];;++idx) { + uint32_t chainhash = chains[idx - gnuhash->symoffset]; + if ((chainhash | 1) == (symhash | 1) && + strcmp(strtab + symtab[idx].st_name, name) == 0) + return &symtab[idx]; + if ((chainhash & 1) != 0) + break; + } + return NULL; +} + static ElfW(Sym) *sym_lookup_dyn(plt_lib lib, const char *name) { - ElfW(Word) *hash = (ElfW(Word)*) lib_dt_lookup(lib, DT_HASH); - ElfW(Sym) *symtab = (ElfW(Sym)*) lib_dt_lookup(lib, DT_SYMTAB); - const char *strtab = (const char*) lib_dt_lookup(lib, DT_STRTAB); + ElfW(Sym) *symtab = lib_dt_lookup(lib, DT_SYMTAB); + const char *strtab = lib_dt_lookup(lib, DT_STRTAB); - if (!hash || !symtab || !strtab) + if (!symtab || !strtab) return NULL; - return elf_hash_find (hash, symtab, strtab, name); + +#ifdef DT_GNU_HASH + // trust GNU hash if we have it. + struct gnu_hash_header *gnu_hash = lib_dt_lookup(lib, DT_GNU_HASH); + if (gnu_hash) + return gnu_hash_find (gnu_hash, symtab, strtab, name); +#endif + + // Look up symbol table using traditional ELF hash. + ElfW(Word) *hash = lib_dt_lookup(lib, DT_HASH); + if (hash) + return elf_hash_find (hash, symtab, strtab, name); + + // XXX: we could do a linear walk of the symbol table here... + return NULL; + } plt_fn *plt_get_real_fn(plt_ctx ctx, const char *name) From 4185c324fcf594ebcb22a1f6a04945966bf7074c Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 5 May 2022 19:25:18 +0100 Subject: [PATCH 08/11] CFI: enable indirect branch tracking on amd64 arch iand Sysv systems to check jmp/call supported by clang and gcc. --- CMakeLists.txt | 5 +++++ src/asm/trampoline-x86_64-systemv.S | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index f15333e..8895d86 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,11 @@ else () set (MMK_ABI "win") else () set (MMK_ABI "systemv") + if (CMAKE_C_COMPILER_ID MATCHES "GNU") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcf-protection") + set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-zibt -Wl,-zshstk") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-zibt -Wl,-zshstk") + endif () endif () set (MMK_ARCH "x86_64") set (MMK_BITS 64) diff --git a/src/asm/trampoline-x86_64-systemv.S b/src/asm/trampoline-x86_64-systemv.S index 56f0efd..01d370c 100644 --- a/src/asm/trampoline-x86_64-systemv.S +++ b/src/asm/trampoline-x86_64-systemv.S @@ -31,11 +31,19 @@ movdqu (%rsp), Reg; \ add $0x10, %rsp +# if defined(__CET__) +# define mmk_cet endbr64 +# else +# define mmk_cet +# endif + .globl MANGLE(mmk_trampoline) MANGLE(mmk_trampoline): start: + mmk_cet call next // Retrieve IP next: + mmk_cet pop %r11 push %r11 // Setup mock context From 321fcc74c1828e73af72cd75460857e1a3a549b9 Mon Sep 17 00:00:00 2001 From: Scott K Logan Date: Thu, 21 Mar 2024 15:13:47 -0500 Subject: [PATCH 09/11] Stop forcing users to build with -Werror Forcing users to build with -Werror only punishes those building with newer compilers or toolchains than those in the repository CI. While maintaining a warning-free build is a noble cause, the repository CI can be adjusted so that it is enforced only for the platforms you're testing and not every single user. --- .travis.yml | 1 + appveyor.yml | 1 + sample/CMakeLists.txt | 2 +- test/CMakeLists.txt | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b8a6f25..a4f29bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -133,6 +133,7 @@ script: -Wno-dev -DCMAKE_BUILD_TYPE=${CONFIGURATION} -DCMAKE_INSTALL_PREFIX=mimick-${TRAVIS_TAG} + -DCMAKE_C_FLAGS="-Werror" ${CMAKE_OPTS} .. - TERM=dumb cmake --build . -- -j4 diff --git a/appveyor.yml b/appveyor.yml index 7b724ef..6b5101e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -61,6 +61,7 @@ install: -DCMAKE_INSTALL_PREFIX="mimick-%RELEASE_NAME%" -DCMAKE_BUILD_TYPE="%CONFIGURATION%" -DCMAKE_SYSTEM_PROCESSOR="%PLATFORM%" + -DCMAKE_C_FLAGS="-Werror" %CMAKE_OPTS% -G "%GENERATOR%" .. diff --git a/sample/CMakeLists.txt b/sample/CMakeLists.txt index f637b75..85745f9 100644 --- a/sample/CMakeLists.txt +++ b/sample/CMakeLists.txt @@ -1,5 +1,5 @@ if (NOT MSVC) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic -Werror") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic") endif () add_subdirectory (strdup) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c0eb41b..1c1aa44 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,5 +1,5 @@ if (NOT MSVC) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic -Werror") + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic") endif () add_library (foo SHARED libfoo.c) From ec9d0dbf629357fc6832927cac71d520c847e2de Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 10 Apr 2025 09:23:04 +0800 Subject: [PATCH 10/11] elf: Fix incorrect ELF type usage in build system The build was failing due to references to non-existent types `ElfAddr` and `ElfOff`. These should be replaced with the correct portable type macros `ElfW(Addr)` and `ElfW(Off)` respectively. --- src/plt-elf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plt-elf.c b/src/plt-elf.c index 1562cab..c2d9645 100644 --- a/src/plt-elf.c +++ b/src/plt-elf.c @@ -94,9 +94,9 @@ static ElfWord lib_dt_lookup_val(plt_lib lib, ElfSWord tag) #if !defined HAVE__R_DEBUG static int find_dynamic(struct dl_phdr_info *info, size_t size, void *data) { - ElfAddr *ctx = data; + ElfW(Addr) *ctx = data; - for (ElfOff i = 0; i < info->dlpi_phnum; ++i) { + for (ElfW(Off) i = 0; i < info->dlpi_phnum; ++i) { if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) { *ctx = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr; return 1; @@ -132,7 +132,7 @@ static struct r_debug *get_r_debug(void) # if defined HAVE__DYNAMIC if (!dbg) { # endif - ElfAddr dynamic; + ElfW(Addr) dynamic; if (dl_iterate_phdr(find_dynamic, &dynamic) > 0) dbg = r_debug_from_dynamic((void *) dynamic); # if defined HAVE__DYNAMIC From 4960dcbb5b9c09ee4565c25a35949fb107844524 Mon Sep 17 00:00:00 2001 From: Michael Carroll Date: Fri, 9 Jan 2026 14:59:51 +0000 Subject: [PATCH 11/11] Remove vestigial functions after merge from upstream Signed-off-by: Michael Carroll --- src/plt-elf.c | 56 --------------------------------------------------- 1 file changed, 56 deletions(-) diff --git a/src/plt-elf.c b/src/plt-elf.c index 95a1de7..ac1443c 100644 --- a/src/plt-elf.c +++ b/src/plt-elf.c @@ -317,15 +317,6 @@ void plt_reset_offsets(plt_offset *offset, size_t nb_off) { } } -static uint32_t elf_gnu_hash(const char *name) { - uint32_t h = 5381; - - for (unsigned char c = *name; c != '\0'; c = *++name) - h = (h << 5) + h + *name; - - return h; -} - static unsigned long elf_hash(const char *s) { unsigned long h = 0, high; while (*s) { @@ -337,53 +328,6 @@ static unsigned long elf_hash(const char *s) { return h; } -static ElfW(Sym) * elf_gnu_hash_find(const ElfW(Word) * gnu_hash, - ElfW(Sym) * symtab, const char *strtab, - const char *name) { - const uint32_t namehash = elf_gnu_hash(name); - - const uint32_t nbuckets = gnu_hash[0]; - const uint32_t symoffset = gnu_hash[1]; - const uint32_t bloom_size = gnu_hash[2]; - const uint32_t bloom_shift = gnu_hash[3]; - const ElfWord *bloom = (void *)&gnu_hash[4]; - const uint32_t *buckets = (void *)&bloom[bloom_size]; - const uint32_t *chain = &buckets[nbuckets]; - - ElfWord word = bloom[(namehash / MMK_BITS) % bloom_size]; - ElfWord mask = 0 | (ElfWord)1 << (namehash % MMK_BITS) | - (ElfWord)1 << ((namehash >> bloom_shift) % MMK_BITS); - - /* If at least one bit is not set, a symbol is surely missing. */ - if ((word & mask) != mask) - return NULL; - - uint32_t symix = buckets[namehash % nbuckets]; - if (symix < symoffset) - return NULL; - - size_t name_len = mmk_strlen(name); - - /* Loop through the chain. */ - while (1) { - const char *symname = strtab + symtab[symix].st_name; - const uint32_t hash = chain[symix - symoffset]; - size_t symname_len = strlen(symname); - size_t cmp_len = (name_len < symname_len) ? name_len : symname_len; - - if ((namehash | 1) == (hash | 1) && mmk_memcmp(name, symname, cmp_len) == 0) - return &symtab[symix]; - - /* Chain ends with an element with the lowest bit set to 1. */ - if (hash & 1) - break; - - symix++; - } - - return NULL; -} - static ElfW(Sym) * elf_hash_find(ElfW(Word) * hash, ElfW(Sym) * symtab, const char *strtab, const char *name) { struct {