From e5c1a78746d962fdbdc9184f29aea727ebe8a05c Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Tue, 21 Feb 2023 00:16:42 +0100 Subject: [PATCH 1/5] ci: Extend with MSVC pass Signed-off-by: Anatol Belski --- .github/workflows/push.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index c82cb70..65e55e0 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -86,3 +86,21 @@ jobs: make CC=gcc TARGET=aarch64 all # FIXME: For some reason some of the object files are rebuilt make CC=gcc TARGET=aarch64 test-ci + + windows: + strategy: + matrix: + arch: [x86, amd64] + include: + - vcpkg_dir: .\win32\vcpkg + - vcpkg_triplet: x86-windows + arch: x86 + - vcpkg_triplet: x64-windows + arch: amd64 + runs-on: windows-2022 + steps: + - uses: actions/checkout@v2 + - uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.arch }} + - run: nmake -nologo -f win32/Makefile VCPKG_DIR=${{ matrix.vcpkg_dir }} VCPKG_TRIPLET=${{ matrix.vcpkg_triplet }} From ec11fc119bc9f1f1661fe08076a5a1dc7afe1522 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Tue, 21 Feb 2023 00:17:57 +0100 Subject: [PATCH 2/5] build: Add MSVC Makefile Signed-off-by: Anatol Belski --- .github/workflows/push.yml | 10 +++- win32/Makefile | 104 +++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 win32/Makefile diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 65e55e0..b18f04e 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -103,4 +103,12 @@ jobs: - uses: ilammy/msvc-dev-cmd@v1 with: arch: ${{ matrix.arch }} - - run: nmake -nologo -f win32/Makefile VCPKG_DIR=${{ matrix.vcpkg_dir }} VCPKG_TRIPLET=${{ matrix.vcpkg_triplet }} + - name: Build + shell: cmd + run: nmake -nologo -f win32/Makefile VCPKG_DIR=${{ matrix.vcpkg_dir }} VCPKG_TRIPLET=${{ matrix.vcpkg_triplet }} + - name: Test + shell: cmd + run: | + nmake -nologo -f win32/Makefile VCPKG_DIR=${{ matrix.vcpkg_dir }} VCPKG_TRIPLET=${{ matrix.vcpkg_triplet }} test + type win32\build_${{ matrix.vcpkg_triplet }}\test.log + diff --git a/win32/Makefile b/win32/Makefile new file mode 100644 index 0000000..30b7842 --- /dev/null +++ b/win32/Makefile @@ -0,0 +1,104 @@ + +!if "$(BUILD)" == "" +BUILD=release +!endif + +!if "$(VCPKG_TRIPLET)" == "" +VCPKG_TRIPLET=$(VSCMD_ARG_TGT_ARCH)-windows +!endif + +!if "$(BUILD_DIR)" == "" +BUILD_DIR=win32\build_$(VCPKG_TRIPLET) +!endif +SRC_DIR=. + +!if "$(VCPKG_DIR)" == "" +VCPKG_DIR=win32\vcpkg +!endif +PATH=$(PATH);$(VCPKG_DIR)\installed\$(VCPKG_TRIPLET)\bin + +CFLAGS=/nologo /utf-8 /W3 /EHsc /Zi /I$(BUILD_DIR) /I$(VCPKG_DIR)\installed\$(VCPKG_TRIPLET)\include +LDFLAGS=/nologo +!if "$(BUILD)" == "release" +CFLAGS=$(CFLAGS) /MT /Ox +!else +CFLAGS=$(CFLAGS) /MTd /Od /DEBUG /D_DEBUG /DIR_DEBUG=1 +LDFLAGS=$(LDFLAGS) /DEBUG +!endif + +!if "$(CC)" == "" +CC=cl.exe +!endif + +!if "$(LD)" == "" +LD=link.exe +!endif + +!if "$(TARGET)" == "" +TARGET = $(VSCMD_ARG_TGT_ARCH) +!endif +!if "$(TARGET)" == "x64" +CFLAGS=$(CFLAGS) /DIR_TARGET_X64 +DASM_ARCH=x86 +DASM_FLAGS=-D X64=1 +!endif +!if "$(TARGET)" == "x86" +CFLAGS=$(CFLAGS) /DIR_TARGET_X86 +DASM_ARCH=x86 +DASM_FLAGS= +!endif + +LDFLAGS=$(LDFLAGS) /libpath:$(VCPKG_DIR)\installed\$(VCPKG_TRIPLET)\lib + +LIBS=psapi.lib capstone.lib + +OBJS_COMMON=$(BUILD_DIR)\ir.obj $(BUILD_DIR)\ir_strtab.obj $(BUILD_DIR)\ir_cfg.obj \ + $(BUILD_DIR)\ir_sccp.obj $(BUILD_DIR)\ir_gcm.obj $(BUILD_DIR)\ir_ra.obj $(BUILD_DIR)\ir_emit.obj \ + $(BUILD_DIR)\ir_load.obj $(BUILD_DIR)\ir_save.obj $(BUILD_DIR)\ir_emit_c.obj $(BUILD_DIR)\ir_dump.obj \ + $(BUILD_DIR)\ir_disasm.obj $(BUILD_DIR)\ir_check.obj +OBJS_IR = $(BUILD_DIR)\ir_main.obj +OBJS_IR_TEST = $(BUILD_DIR)\ir_test.obj + +all: $(BUILD_DIR)\ir.exe + +$(BUILD_DIR)\ir.exe: builddir capstone $(BUILD_DIR)\ir_emit_$(DASM_ARCH).h $(BUILD_DIR)\ir_fold_hash.h $(OBJS_IR) $(OBJS_COMMON) + "$(LD)" $(LDFLAGS) $(OBJS_COMMON) $(OBJS_IR) $(LIBS) /out:$@ + +$(BUILD_DIR)\ir_fold_hash.h: $(BUILD_DIR)\gen_ir_fold_hash.exe $(SRC_DIR)\ir_fold.h $(SRC_DIR)\ir.h + $(BUILD_DIR)\gen_ir_fold_hash.exe < $(SRC_DIR)\ir_fold.h > $(BUILD_DIR)\ir_fold_hash.h +$(BUILD_DIR)\gen_ir_fold_hash.exe: $(SRC_DIR)\gen_ir_fold_hash.c $(SRC_DIR)\ir_strtab.c + "$(CC)" $(CFLAGS) /Fo$(BUILD_DIR)\ /Fe$@ $** + +$(BUILD_DIR)\minilua.exe: $(SRC_DIR)\dynasm\minilua.c + "$(CC)" /Fo$(BUILD_DIR)\ /Fe$@ $** +$(BUILD_DIR)\ir_emit_$(DASM_ARCH).h: $(BUILD_DIR)\minilua.exe + $(BUILD_DIR)\minilua.exe $(SRC_DIR)\dynasm\dynasm.lua $(DASM_FLAGS) -o $@ $(SRC_DIR)\ir_$(DASM_ARCH).dasc + +{$(SRC_DIR)}.c{$(BUILD_DIR)}.obj: + "$(CC)" $(CFLAGS) /Fo$@ /c $< + +# If the vcpkg dir exists, lets assume we're good with the deps. +!if !exist($(VCPKG_DIR)) +vcpkg: + git clone https://github.com/Microsoft/vcpkg.git "$(VCPKG_DIR)" + "$(VCPKG_DIR)\bootstrap-vcpkg.bat" +!else +vcpkg: +!endif + +capstone: vcpkg + "$(VCPKG_DIR)\vcpkg.exe" install --triplet=$(VCPKG_TRIPLET) capstone + +!if !exist($(BUILD_DIR)) +builddir: + md "$(BUILD_DIR)" +!else +builddir: +!endif + +test: $(BUILD_DIR)\ir.exe + $(BUILD_DIR)\ir.exe $(SRC_DIR)\test.ir --dump --save $(BUILD_DIR)\test.log + +clean: + del /f /q $(BUILD_DIR)\*.obj $(BUILD_DIR)\*.exe $(BUILD_DIR)\*.pdb $(BUILD_DIR)\*.ilk $(BUILD_DIR)\*.h + From 39c658b5d5647585bac4d703311937ec96ad117f Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Tue, 21 Feb 2023 00:18:34 +0100 Subject: [PATCH 3/5] gitignore: Extend with some win32/ paths Signed-off-by: Anatol Belski --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index bdb9077..7d504ac 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ tests/**/*.exp tests/**/*.ir tests/**/*.out tests/**/*.log + +win32/vcpkg +win32/build_* From 964f5a01912c9fbe84d43f5a9faf040f85ffeddc Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Tue, 21 Feb 2023 00:19:03 +0100 Subject: [PATCH 4/5] build: MSVC compatibility Signed-off-by: Anatol Belski --- ir.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++-- ir.h | 26 ++++++++++++++++++++++---- ir_emit.c | 27 +++++++++++++++++++++++--- ir_gcm.c | 2 +- ir_load.c | 2 ++ ir_main.c | 4 +++- ir_private.h | 30 +++++++++++++++++++++++------ ir_ra.c | 11 ++++++++++- ir_strtab.c | 2 +- 9 files changed, 138 insertions(+), 19 deletions(-) diff --git a/ir.c b/ir.c index dc7e79f..7e83ae3 100644 --- a/ir.c +++ b/ir.c @@ -18,7 +18,12 @@ # define _GNU_SOURCE #endif -#include +#ifndef _WIN32 +# include +#else +# define WIN32_LEAN_AND_MEAN +# include +#endif #include "ir.h" #include "ir_private.h" @@ -1125,7 +1130,7 @@ void ir_hashtab_init(ir_hashtab *tab, uint32_t size) void ir_hashtab_free(ir_hashtab *tab) { uint32_t hash_size = (uint32_t)(-(int32_t)tab->mask); - char *data = tab->data - (hash_size * sizeof(uint32_t)); + char *data = (char*)tab->data - (hash_size * sizeof(uint32_t)); ir_mem_free(data); tab->data = NULL; } @@ -1209,6 +1214,49 @@ void ir_hashtab_key_sort(ir_hashtab *tab) } /* Memory API */ +#ifdef _WIN32 +void *ir_mem_mmap(size_t size) +{ + void *ret; + +#ifdef _M_X64 + DWORD size_hi = size >> 32, size_lo = size & 0xffffffff; +#else + DWORD size_hi = size, size_lo = 0; +#endif + + HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, size_hi, size_lo, NULL); + + ret = MapViewOfFile(h, FILE_MAP_COPY | FILE_MAP_EXECUTE, size_hi, size_lo, size); + if (!ret) { + CloseHandle(h); + } + + return ret; +} + +int ir_mem_unmap(void *ptr, size_t size) +{ + /* XXX file handle is leaked. */ + UnmapViewOfFile(ptr); + return 1; +} + +int ir_mem_protect(void *ptr, size_t size) +{ + return 1; +} + +int ir_mem_unprotect(void *ptr, size_t size) +{ + return 1; +} + +int ir_mem_flush(void *ptr, size_t size) +{ + return 1; +} +#else void *ir_mem_mmap(size_t size) { return mmap(NULL, size, PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); @@ -1242,6 +1290,7 @@ int ir_mem_flush(void *ptr, size_t size) #endif return 1; } +#endif /* Alias Analyses */ typedef enum _ir_alias { diff --git a/ir.h b/ir.h index 3bc34aa..0bd9090 100644 --- a/ir.h +++ b/ir.h @@ -16,6 +16,20 @@ #define IR_VERSION "0.0.1" +#ifdef _WIN32 +/* TODO Handle ARM, too. */ +# if defined(_M_X64) +# define __SIZEOF_SIZE_T__ 8 +# elif defined(_M_IX86) +# define __SIZEOF_SIZE_T__ 4 +# endif +/* Only supported is little endian for any arch on Windows, + so just fake the same for all. */ +# define __ORDER_LITTLE_ENDIAN__ 1 +# define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ +# define __has_builtin(arg) (0) +#endif + #if defined(IR_TARGET_X86) # define IR_TARGET "x86" #elif defined(IR_TARGET_X64) @@ -326,6 +340,11 @@ typedef int32_t ir_ref; #define IR_LAST_FOLDABLE_OP IR_COPY /* IR Constant Value */ +#ifndef IR_64 +# define ADDR_MEMBER uintptr_t addr; +#else +# define ADDR_MEMBER +#endif typedef union _ir_val { double d; uint64_t u64; @@ -338,9 +357,7 @@ typedef union _ir_val { uint32_t u32; int32_t i32; float f; -#ifndef IR_64 - uintptr_t addr; -#endif + ADDR_MEMBER IR_STRUCT_LOHI( union { uint16_t u16; @@ -361,6 +378,7 @@ typedef union _ir_val { uint32_t u32_hi ); } ir_val; +#undef ADDR_MEMBER /* IR constant flags */ #define IR_CONST_EMIT (1<<0) @@ -374,7 +392,7 @@ typedef struct _ir_insn { union { IR_STRUCT_LOHI( uint8_t op, - uint8_t type; + uint8_t type ); uint16_t opt; }, diff --git a/ir_emit.c b/ir_emit.c index 7bf62c0..9b60f8a 100644 --- a/ir_emit.c +++ b/ir_emit.c @@ -16,7 +16,13 @@ #endif #include "ir_private.h" -#include +#ifndef _WIN32 +# include +#else +# define WIN32_LEAN_AND_MEAN +# include +# include +#endif #define DASM_M_GROW(ctx, t, p, sz, need) \ do { \ @@ -202,10 +208,25 @@ static void *ir_resolve_sym_name(const char *name) void *handle = NULL; void *addr; -#ifdef RTLD_DEFAULT +#ifndef _WIN32 +# ifdef RTLD_DEFAULT handle = RTLD_DEFAULT; -#endif +# endif addr = dlsym(handle, name); +#else + HMODULE mods[256]; + DWORD cbNeeded; + uint32_t i = 0; + + addr = NULL; + + EnumProcessModules(GetCurrentProcess(), mods, sizeof(mods), &cbNeeded); + + while(!addr && i < (cbNeeded / sizeof(HMODULE))) { + addr = GetProcAddress(mods[i], name); + i++; + } +#endif IR_ASSERT(addr != NULL); return addr; } diff --git a/ir_gcm.c b/ir_gcm.c index 9ae8d31..3e49b4d 100644 --- a/ir_gcm.c +++ b/ir_gcm.c @@ -370,7 +370,7 @@ static void ir_xlat_binding(ir_ctx *ctx, ir_ref *_xlat) ir_hashtab *binding = ctx->binding; uint32_t hash_size = (uint32_t)(-(int32_t)binding->mask); - memset(binding->data - (hash_size * sizeof(uint32_t)), -1, hash_size * sizeof(uint32_t)); + memset((char*)binding->data - (hash_size * sizeof(uint32_t)), -1, hash_size * sizeof(uint32_t)); n1 = binding->count; n2 = 0; pos = 0; diff --git a/ir_load.c b/ir_load.c index ea28d16..b7fc1ef 100644 --- a/ir_load.c +++ b/ir_load.c @@ -15,7 +15,9 @@ #include #include +#ifndef _WIN32 #include +#endif const unsigned char *yy_buf; const unsigned char *yy_end; diff --git a/ir_main.c b/ir_main.c index 35722da..6c74fd9 100644 --- a/ir_main.c +++ b/ir_main.c @@ -355,7 +355,7 @@ int main(int argc, char **argv) return 1; } - f = fopen(input, "r"); + f = fopen(input, "rb"); if (!f) { fprintf(stderr, "ERROR: Cannot open input file '%s'\n", input); return 1; @@ -420,6 +420,7 @@ int main(int argc, char **argv) int (*func)(void) = entry; int ret; +#ifndef _WIN32 ir_perf_map_register("test", entry, size); ir_perf_jitdump_open(); ir_perf_jitdump_register("test", entry, size); @@ -427,6 +428,7 @@ int main(int argc, char **argv) ir_mem_unprotect(entry, 4096); ir_gdb_register("test", entry, size, sizeof(void*), 0); ir_mem_protect(entry, 4096); +#endif ret = func(); fflush(stdout); diff --git a/ir_private.h b/ir_private.h index dba6e89..7ba882b 100644 --- a/ir_private.h +++ b/ir_private.h @@ -17,6 +17,16 @@ # define IR_ASSERT(x) #endif +#ifdef _WIN32 +# include +# ifdef _M_X64 +# pragma intrinsic(_BitScanForward64) +# pragma intrinsic(_BitScanReverse64) +# endif +# pragma intrinsic(_BitScanForward) +# pragma intrinsic(_BitScanReverse) +#endif + #ifdef __has_builtin # if __has_builtin(__builtin_expect) # define EXPECTED(condition) __builtin_expect(!!(condition), 1) @@ -104,7 +114,7 @@ IR_ALWAYS_INLINE uint32_t ir_ntz(uint32_t num) #elif defined(_WIN32) uint32_t index; - if (!BitScanForward(&index, num)) { + if (!_BitScanForward(&index, num)) { /* undefined behavior */ return 32; } @@ -133,9 +143,9 @@ IR_ALWAYS_INLINE uint32_t ir_ntzl(uint64_t num) unsigned long index; #if defined(_WIN64) - if (!BitScanForward64(&index, num)) { + if (!_BitScanForward64(&index, num)) { #else - if (!BitScanForward(&index, num)) { + if (!_BitScanForward(&index, num)) { #endif /* undefined behavior */ return 64; @@ -165,7 +175,7 @@ IR_ALWAYS_INLINE int ir_nlz(uint32_t num) #elif defined(_WIN32) uint32_t index; - if (!BitScanReverse(&index, num)) { + if (!_BitScanReverse(&index, num)) { /* undefined behavior */ return 32; } @@ -192,7 +202,11 @@ IR_ALWAYS_INLINE int ir_nlzl(uint64_t num) #elif defined(_WIN32) uint32_t index; - if (!BitScanReverse64(&index, num)) { +#if defined(_WIN64) + if (!_BitScanReverse64(&index, num)) { +#else + if (!_BitScanReverse(&index, num)) { +#endif /* undefined behavior */ return 64; } @@ -223,7 +237,11 @@ IR_ALWAYS_INLINE int ir_nlzl(uint64_t num) # define ir_bitset_ntz ir_ntz #else # define IR_BITSET_BITS 64 -# define IR_BITSET_ONE 1UL +# ifdef _M_X64 /* MSVC*/ +# define IR_BITSET_ONE 1ui64 +# else +# define IR_BITSET_ONE 1UL +# endif # define ir_bitset_base_t uint64_t # define ir_bitset_ntz ir_ntzl #endif diff --git a/ir_ra.c b/ir_ra.c index 1ae31f6..d4bfb05 100644 --- a/ir_ra.c +++ b/ir_ra.c @@ -862,7 +862,11 @@ static void ir_add_phi_move(ir_ctx *ctx, uint32_t b, ir_ref from, ir_ref to) } } +#ifndef _WIN32 static int ir_block_cmp(const void *b1, const void *b2, void *data) +#else +static int ir_block_cmp(void *data, const void *b1, const void *b2) +#endif { ir_ctx *ctx = data; int d1 = ctx->cfg_blocks[*(ir_ref*)b1].loop_depth; @@ -1047,7 +1051,12 @@ int ir_coalesce(ir_ctx *ctx) } } - qsort_r(blocks.l.a.refs, ir_worklist_len(&blocks), sizeof(ir_ref), ir_block_cmp, ctx); +#ifndef _WIN32 +# define qsort_fn qsort_r +#else +# define qsort_fn qsort_s +#endif + qsort_fn(blocks.l.a.refs, ir_worklist_len(&blocks), sizeof(ir_ref), ir_block_cmp, ctx); while (ir_worklist_len(&blocks)) { uint32_t i; diff --git a/ir_strtab.c b/ir_strtab.c index 8c68ab2..2ef502b 100644 --- a/ir_strtab.c +++ b/ir_strtab.c @@ -206,7 +206,7 @@ const char *ir_strtab_str(ir_strtab *strtab, ir_ref idx) void ir_strtab_free(ir_strtab *strtab) { uint32_t hash_size = (uint32_t)(-(int32_t)strtab->mask); - char *data = strtab->data - (hash_size * sizeof(uint32_t)); + char *data = (char*)strtab->data - (hash_size * sizeof(uint32_t)); ir_mem_free(data); strtab->data = NULL; if (strtab->buf) { From 992d2d4f3a902cbffd2eb51fb369c6f0b3554b33 Mon Sep 17 00:00:00 2001 From: Anatol Belski Date: Thu, 23 Feb 2023 00:17:23 +0100 Subject: [PATCH 5/5] github: Set more descriptive job names Signed-off-by: Anatol Belski --- .github/workflows/push.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index b18f04e..aad33ee 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -9,8 +9,8 @@ on: permissions: contents: read jobs: - x86_64: - name: x86_64 + Linux_x86_64: + name: 'Linux x86_64' runs-on: ubuntu-22.04 container: image: ubuntu:22.04 @@ -29,8 +29,8 @@ jobs: run: make TARGET=x86_64 all - name: test run: make TARGET=x86_64 test-ci - x86: - name: x86 + Linux_i386: + name: 'Linux i386' runs-on: ubuntu-22.04 container: image: ubuntu:22.04 @@ -61,8 +61,8 @@ jobs: run: make TARGET=x86 all - name: test run: make TARGET=x86 test-ci - aarch64: - name: aarch64 + Linux_aarch64: + name: 'Linux aarch64' runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 @@ -87,7 +87,7 @@ jobs: # FIXME: For some reason some of the object files are rebuilt make CC=gcc TARGET=aarch64 test-ci - windows: + Windows: strategy: matrix: arch: [x86, amd64]