diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1ea19495..cd1379c0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,16 +34,13 @@ jobs: timeout-minutes: 6 steps: - uses: actions/checkout@v4 - - name: build tcc (x86_64-win32) + - name: build & test (x86_64-win32) shell: cmd run: | cd win32 for /f "delims=" %%i in ('vswhere.exe -latest -property installationPath') do call "%%i\VC\Auxiliary\Build\vcvarsall.bat" amd64 call build-tcc.bat -c cl -t x86_64 - - name: test (x86_64-win32) - shell: cmd - run: | - cd tests + cd ..\tests call test-win32.bat all -k test-i386-win32: @@ -51,16 +48,13 @@ jobs: timeout-minutes: 6 steps: - uses: actions/checkout@v4 - - name: build tcc (i386-win32) + - name: build & test (i386-win32) shell: cmd run: | cd win32 for /f "delims=" %%i in ('vswhere.exe -latest -property installationPath') do call "%%i\VC\Auxiliary\Build\vcvarsall.bat" x86 call build-tcc.bat -c cl -t i386 - - name: test (i386-win32) - shell: cmd - run: | - cd tests + cd ..\tests call test-win32.bat -p c:\mingw32\bin all -k test-arm64-win32: @@ -72,9 +66,8 @@ jobs: shell: cmd run: | cd win32 - for /f "delims=" %%i in ('vswhere.exe -latest -property installationPath') do call "%%i\VC\Auxiliary\Build\vcvarsall.bat" amd64_arm64 + for /f "delims=" %%i in ('vswhere.exe -latest -property installationPath') do call "%%i\VC\Auxiliary\Build\vcvarsall.bat" arm64 call build-tcc.bat -c cl -t arm64 - set "PATH=C:\Program Files\LLVM\bin;%CD%;%PATH%" cd ..\tests call test-win32.bat -c clang all -k @@ -132,12 +125,25 @@ jobs: echo "::endgroup::" # flatten 'run container' ./configure && make && make test -k - test-riscv64-linux-native: - runs-on: ubuntu-24.04-riscv - timeout-minutes: 8 +# test-riscv64-linux-native: +# runs-on: ubuntu-24.04-riscv +# timeout-minutes: 8 +# steps: +# - uses: actions/checkout@v4 +# - name: make & test tcc (riscv64-linux native) +# run: | +# uname -m # riscv64 +# ./configure && make && make test -k + + test-i386-linux: + runs-on: ubuntu-latest + timeout-minutes: 3 steps: - uses: actions/checkout@v4 - - name: make & test tcc (riscv64-linux native) + - name: install i386-gcc run: | - uname -m # riscv64 - ./configure && make && make test -k + sudo dpkg --add-architecture i386 + sudo apt-get update -q -y + sudo apt-get install -q -y gcc-multilib libc6-dev:i386 + - name: make & test tcc (i386-linux) + run: ./configure --cpu=i386 --cc="gcc -m32" && make && make test -k diff --git a/i386-gen.c b/i386-gen.c index 83ecaa34..d57c6ed1 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -439,7 +439,7 @@ ST_FUNC void store(int r, SValue *v) } else #endif - if ((fr & VT_SYM) && v->sym->type.t & VT_TLS) { + if ((v->r & VT_SYM) && v->sym->type.t & VT_TLS) { o(0x65); /* gs segment prefix */ o(opc); o(0x04 | (REG_VALUE(r) << 3)); /* modrm: [sib] | srcreg */ @@ -467,7 +467,7 @@ static void gadd_sp(int val) } } -#if defined CONFIG_TCC_BCHECK || defined TCC_TARGET_PE || defined CONFIG_TCC_PIC +#if defined TCC_TARGET_PE || defined CONFIG_TCC_PIC static void gen_static_call(int v) { Sym *sym; diff --git a/lib/Makefile b/lib/Makefile index 51c901d8..99e8b58d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -73,7 +73,7 @@ OBJ-arm-vfp = $(OBJ-arm) OBJ-arm-eabi = $(OBJ-arm) OBJ-arm-eabihf = $(OBJ-arm) OBJ-arm-wince = $(ARM_O) $(WIN_O) -OBJ-riscv64 = $(RISCV64_O) lib-riscv.o $(LIN_O) +OBJ-riscv64 = $(RISCV64_O) armflush.o $(LIN_O) OBJ-extra = $(filter $(EXTRA_O),$(OBJ-$T)) OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T))) diff --git a/lib/armflush.c b/lib/armflush.c index d3ee99e7..6ec11f38 100644 --- a/lib/armflush.c +++ b/lib/armflush.c @@ -61,4 +61,10 @@ void __clear_cache(void *beg, void *end) } /* ------------------------------------------------------------- */ +#elif defined __riscv +void __clear_cache(void *beg, void *end) +{ + __riscv64_clear_cache(beg, end); +} + #endif diff --git a/lib/lib-riscv.c b/lib/lib-riscv.c deleted file mode 100644 index b76220c3..00000000 --- a/lib/lib-riscv.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * TCC runtime library for riscv64. - * - * Copyright (c) 2026 - * - * Copying and distribution of this file, with or without modification, - * are permitted in any medium without royalty provided the copyright - * notice and this notice are preserved. This file is offered as-is, - * without any warranty. - */ - -/* ------------------------------------------------------------- */ -/* __clear_cache is used in tccrun.c. It is a built-in - intrinsic with gcc. However tcc in order to compile - itself needs this function */ - -void __clear_cache(void *beg, void *end) -{ - __riscv64_clear_cache(beg, end); -} diff --git a/libtcc.c b/libtcc.c index 1de825b3..d3d27d75 100644 --- a/libtcc.c +++ b/libtcc.c @@ -899,6 +899,9 @@ LIBTCCAPI TCCState *tcc_new(void) #ifdef TCC_ARM_HARDFLOAT s->float_abi = ARM_HARD_FLOAT; #endif +#if defined TCC_TARGET_ARM64 && defined TCC_TARGET_PE + s->pe_dll_characteristics = 0x8160; +#endif #ifdef CONFIG_NEW_DTAGS s->enable_new_dtags = 1; #endif @@ -1365,7 +1368,7 @@ struct lopt { static int link_option(struct lopt *o, const char *q) { const char *p; - int c; + int c, r; redo: /* there should be 1 or 2 dashes */ p = o->opt; @@ -1373,6 +1376,16 @@ redo: return 0; if (*p == '-') p++; + r = 1; + if (q[0] == '?') { /* check for no-/disable- prefix */ + ++q; + if (p[0] == 'n' && p[1] == 'o' && p[2] == '-') + p += 3, r = -1; +#ifdef TCC_TARGET_PE + else if (0 == memcmp(p, "disable-", 8)) + p += 8, r = -1; +#endif + } while ((c = *q) == *p) { if (c == '\0') goto succ; /* -Wl,-opt */ @@ -1401,24 +1414,13 @@ redo: succ: o->arg = p; //printf("set %s '%s'\n", o->opt, o->arg); - return 1; + return r; } static void args_parser_add_file(TCCState *s, const char* filename, int filetype); -#ifdef TCC_TARGET_PE -static void tcc_pe_set_dll_characteristics(TCCState *s, unsigned flags) -{ - s->pe_dll_characteristics |= flags; - s->pe_dll_characteristics_clear &= ~flags; -} - -static void tcc_pe_clear_dll_characteristics(TCCState *s, unsigned flags) -{ - s->pe_dll_characteristics &= ~flags; - s->pe_dll_characteristics_clear |= flags; -} -#endif +#define SET_OR_CLEAR(v,f) (v = r > 0 ? v | f : v & ~f) +#define SET_OR_CLEAR_2(v,f1,f2) (v = r > 0 ? v | f1 : v & ~f2) /* set linker options */ static int tcc_set_linker(TCCState *s, const char *optarg) @@ -1431,6 +1433,7 @@ static int tcc_set_linker(TCCState *s, const char *optarg) char *end = NULL; int ignoring = 0; struct lopt o = {0}; + int r; o.s = s; o.opt = s->link_argv[s->link_optind]; @@ -1481,39 +1484,21 @@ static int tcc_set_linker(TCCState *s, const char *optarg) s->section_align = strtoul(o.arg, &end, 16); } else if (link_option(&o, "soname=|install_name=")) { tcc_set_str(&s->soname, o.arg); - } else if (link_option(&o, "whole-archive")) { - s->filetype |= AFF_WHOLE_ARCHIVE; - } else if (link_option(&o, "no-whole-archive")) { - s->filetype &= ~AFF_WHOLE_ARCHIVE; + } else if (!!(r = link_option(&o, "?whole-archive"))) { + SET_OR_CLEAR(s->filetype, AFF_WHOLE_ARCHIVE); } else if (link_option(&o, "znodelete")) { s->znodelete = 1; #ifdef TCC_TARGET_PE } else if (link_option(&o, "large-address-aware")) { - s->pe_characteristics |= PE_IMAGE_FILE_LARGE_ADDRESS_AWARE; - } else if (link_option(&o, "dynamicbase")) { - tcc_pe_set_dll_characteristics(s, PE_DLLCHARACTERISTICS_DYNAMIC_BASE); - } else if (link_option(&o, "disable-dynamicbase|no-dynamicbase")) { - tcc_pe_clear_dll_characteristics(s, - PE_DLLCHARACTERISTICS_DYNAMIC_BASE | - PE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA); - } else if (link_option(&o, "nxcompat")) { - tcc_pe_set_dll_characteristics(s, PE_DLLCHARACTERISTICS_NX_COMPAT); - } else if (link_option(&o, "disable-nxcompat|no-nxcompat")) { - tcc_pe_clear_dll_characteristics(s, PE_DLLCHARACTERISTICS_NX_COMPAT); - } else if (link_option(&o, "high-entropy-va")) { -# if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64) - tcc_pe_set_dll_characteristics(s, - PE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | - PE_DLLCHARACTERISTICS_DYNAMIC_BASE); -# else - goto err; -# endif - } else if (link_option(&o, "disable-high-entropy-va|no-high-entropy-va")) { - tcc_pe_clear_dll_characteristics(s, PE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA); - } else if (link_option(&o, "tsaware")) { - tcc_pe_set_dll_characteristics(s, PE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE); - } else if (link_option(&o, "disable-tsaware|no-tsaware")) { - tcc_pe_clear_dll_characteristics(s, PE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE); + s->pe_characteristics |= 0x20; + } else if (!!(r = link_option(&o, "?dynamicbase"))) { + SET_OR_CLEAR_2(s1->pe_dll_characteristics, 0x40, 0x60); + } else if (!!(r = link_option(&o, "?high-entropy-va"))) { + SET_OR_CLEAR_2(s1->pe_dll_characteristics, 0x60, 0x20); + } else if (!!(r = link_option(&o, "?nxcompat"))) { + SET_OR_CLEAR(s1->pe_dll_characteristics, 0x100); + } else if (!!(r = link_option(&o, "?tsaware"))) { + SET_OR_CLEAR(s1->pe_dll_characteristics, 0x8000); } else if (link_option(&o, "file-alignment=")) { s->pe_file_align = strtoul(o.arg, &end, 16); } else if (link_option(&o, "stack=")) { diff --git a/tcc-doc.texi b/tcc-doc.texi index 22d6d0a0..6a1870ae 100644 --- a/tcc-doc.texi +++ b/tcc-doc.texi @@ -386,9 +386,7 @@ Set type for PE (Windows) executables. @item -Wl,-[Ttext=# | section-alignment=# | file-alignment=# | image-base=# | stack=#] Modify executable layout. -@item -Wl,-[dynamicbase | nxcompat | high-entropy-va | tsaware] -@item -Wl,-[no-dynamicbase | no-nxcompat | no-high-entropy-va | no-tsaware] -@item -Wl,-[disable-dynamicbase | disable-nxcompat | disable-high-entropy-va | disable-tsaware] +@item -Wl,-(no-|disable-)[dynamicbase | nxcompat | high-entropy-va | tsaware] Set or clear PE (Windows) executable header hardening flags. The @option{-Wl,-high-entropy-va} option is supported on x86-64 and ARM64 PE targets and implies @option{-Wl,-dynamicbase}. Clearing dynamicbase also diff --git a/tcc.h b/tcc.h index d22ed534..b385d72f 100644 --- a/tcc.h +++ b/tcc.h @@ -727,15 +727,6 @@ struct sym_attr { #endif }; -#ifdef TCC_TARGET_PE -#define PE_IMAGE_FILE_RELOCS_STRIPPED 0x0001 -#define PE_IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 -#define PE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020 -#define PE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 -#define PE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 -#define PE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 -#endif - struct TCCState { unsigned char verbose; /* if true, display some information during compilation */ unsigned char nostdinc; /* if true, no standard headers are added */ @@ -949,7 +940,6 @@ struct TCCState { int pe_subsystem; unsigned pe_characteristics; unsigned pe_dll_characteristics; - unsigned pe_dll_characteristics_clear; unsigned pe_file_align; unsigned pe_stack_size; addr_t pe_imagebase; diff --git a/tccelf.c b/tccelf.c index 6d3700a2..1453a7f5 100644 --- a/tccelf.c +++ b/tccelf.c @@ -2992,6 +2992,10 @@ static int elf_output_file(TCCState *s1, const char *filename) create_arm_attribute_section (s1); #endif +#ifdef TCC_TARGET_RISCV64 + create_riscv_attribute_section(s1); +#endif + #if TARGETOS_OpenBSD dyninf.note = create_bsd_note_section (s1, ".note.openbsd.ident", "OpenBSD"); #endif @@ -3172,9 +3176,6 @@ static int elf_output_obj(TCCState *s1, const char *filename) { Section *s; int i, ret, file_offset; -#ifdef TCC_TARGET_RISCV64 - create_riscv_attribute_section(s1); -#endif /* Allocate strings for section names */ alloc_sec_names(s1, 1); file_offset = (sizeof (ElfW(Ehdr)) + 3) & -4; diff --git a/tccgen.c b/tccgen.c index 8806f0ed..333dcbaf 100644 --- a/tccgen.c +++ b/tccgen.c @@ -3280,6 +3280,8 @@ again: dbt_bt = dbt & VT_BTYPE; sbt_bt = sbt & VT_BTYPE; if (dbt_bt == VT_VOID) { + /* do not confuse backends with VT_VOID in registers */ + vpop(), vpushi(0); goto done; } if (sbt_bt == VT_VOID) { diff --git a/tccpe.c b/tccpe.c index 2304c99e..2148517d 100644 --- a/tccpe.c +++ b/tccpe.c @@ -27,54 +27,78 @@ #define stricmp strcasecmp #define strnicmp strncasecmp #include /* chmod() */ -#else -#include #endif -#ifdef TCC_TARGET_X86_64 -# define ADDR3264 ULONGLONG -# define PE_IMAGE_REL IMAGE_REL_BASED_DIR64 +#if defined TCC_TARGET_X86_64 # define REL_TYPE_DIRECT R_X86_64_64 # define R_XXX_THUNKFIX R_X86_64_PC32 # define R_XXX_RELATIVE R_X86_64_RELATIVE # define R_XXX_FUNCCALL R_X86_64_PLT32 -# define IMAGE_FILE_MACHINE 0x8664 # define RSRC_RELTYPE 3 +# define IMAGE_FILE_MACHINE 0x8664 +# define CHARACTERISTICS_EXE 0x022F +# define CHARACTERISTICS_DLL 0x222E +# define IMAGE_BASE_EXE 0x00400000 +# define IMAGE_BASE_DLL 0x10000000 +# define DLLCHARACTERISTICS 0 +# define OS_VER 0x0400 #elif defined TCC_TARGET_ARM -# define ADDR3264 DWORD -# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW # define REL_TYPE_DIRECT R_ARM_ABS32 # define R_XXX_THUNKFIX R_ARM_ABS32 # define R_XXX_RELATIVE R_ARM_RELATIVE # define R_XXX_FUNCCALL R_ARM_PC24 # define R_XXX_FUNCCALL2 R_ARM_ABS32 -# define IMAGE_FILE_MACHINE 0x01C0 # define RSRC_RELTYPE 7 /* ??? (not tested) */ +# define IMAGE_FILE_MACHINE 0x01C0 +# define CHARACTERISTICS_EXE 0x010F +# define CHARACTERISTICS_DLL 0x230F +# define IMAGE_BASE_EXE 0x00100000 +# define IMAGE_BASE_DLL 0x10000000 +# define DLLCHARACTERISTICS 0 +# define OS_VER 0x0400 #elif defined TCC_TARGET_ARM64 -# define ADDR3264 ULONGLONG -# define PE_IMAGE_REL IMAGE_REL_BASED_DIR64 # define REL_TYPE_DIRECT R_AARCH64_ABS64 # define R_XXX_THUNKFIX R_AARCH64_ABS64 # define R_XXX_RELATIVE R_AARCH64_RELATIVE # define R_XXX_FUNCCALL R_AARCH64_CALL26 -# define IMAGE_FILE_MACHINE 0xAA64 # define RSRC_RELTYPE 3 +# define IMAGE_FILE_MACHINE 0xAA64 +# define CHARACTERISTICS_EXE 0x0022 +# define CHARACTERISTICS_DLL 0x2022 +# define IMAGE_BASE_EXE 0x140000000ULL +# define IMAGE_BASE_DLL 0x180000000ULL +# define OS_VER 0x0602 +# define DLLCHARACTERISTICS 0x8160 #elif defined TCC_TARGET_I386 -# define ADDR3264 DWORD -# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW # define REL_TYPE_DIRECT R_386_32 # define R_XXX_THUNKFIX R_386_32 # define R_XXX_RELATIVE R_386_RELATIVE # define R_XXX_FUNCCALL R_386_PC32 -# define IMAGE_FILE_MACHINE 0x014C # define RSRC_RELTYPE 7 /* DIR32NB */ +# define IMAGE_FILE_MACHINE 0x014C +# define CHARACTERISTICS_EXE 0x030F +# define CHARACTERISTICS_DLL 0x230E +# define IMAGE_BASE_EXE 0x00400000 +# define IMAGE_BASE_DLL 0x10000000 +# define OS_VER 0x0400 +# define DLLCHARACTERISTICS 0 +#endif +#if PTR_SIZE == 8 +# define ADDR3264 ULONGLONG +# define PE_MAGIC 0x020B +# define PE_IMAGE_REL IMAGE_REL_BASED_DIR64 +#else +# define ADDR3264 DWORD +# define PE_MAGIC 0x010B +# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW #endif #ifndef IMAGE_NT_SIGNATURE +/* cross compiler: windows.h was not included */ /* ----------------------------------------------------------- */ /* definitions below are from winnt.h */ @@ -107,7 +131,6 @@ typedef struct _IMAGE_DOS_HEADER { /* DOS .EXE header */ } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; #define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ -#define SIZE_OF_NT_SIGNATURE 4 typedef struct _IMAGE_FILE_HEADER { WORD Machine; @@ -138,7 +161,7 @@ typedef struct _IMAGE_OPTIONAL_HEADER { DWORD SizeOfUninitializedData; DWORD AddressOfEntryPoint; DWORD BaseOfCode; -#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64) +#if PTR_SIZE == 4 DWORD BaseOfData; #endif /* NT additional fields. */ @@ -237,19 +260,6 @@ typedef struct _IMAGE_BASE_RELOCATION { #define IMAGE_SIZEOF_BASE_RELOCATION 8 -#ifndef IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA -#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA PE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA -#endif -#ifndef IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE -#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE PE_DLLCHARACTERISTICS_DYNAMIC_BASE -#endif -#ifndef IMAGE_DLLCHARACTERISTICS_NX_COMPAT -#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT PE_DLLCHARACTERISTICS_NX_COMPAT -#endif -#ifndef IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE -#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE PE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE -#endif - #define IMAGE_REL_BASED_ABSOLUTE 0 #define IMAGE_REL_BASED_HIGH 1 #define IMAGE_REL_BASED_LOW 2 @@ -269,34 +279,19 @@ typedef struct _IMAGE_BASE_RELOCATION { #define IMAGE_SCN_MEM_READ 0x40000000 #define IMAGE_SCN_MEM_WRITE 0x80000000 +#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020 +#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 +#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 +#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000 + +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 + #pragma pack(pop) /* ----------------------------------------------------------- */ #endif /* ndef IMAGE_NT_SIGNATURE */ /* ----------------------------------------------------------- */ -static WORD pe_get_dll_characteristics(TCCState *s1) -{ - unsigned v = 0; - -#ifdef TCC_TARGET_ARM64 - v = PE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | - PE_DLLCHARACTERISTICS_DYNAMIC_BASE | - PE_DLLCHARACTERISTICS_NX_COMPAT | - PE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE; -#endif - v |= s1->pe_dll_characteristics; - v &= ~s1->pe_dll_characteristics_clear; - return v; -} - -#ifndef IMAGE_FILE_MACHINE_ARM64 -#define IMAGE_FILE_MACHINE_ARM64 0xAA64 -#endif -#ifndef IMAGE_REL_BASED_DIR64 -# define IMAGE_REL_BASED_DIR64 10 -#endif - #pragma pack(push, 1) struct pe_header { @@ -304,7 +299,7 @@ struct pe_header BYTE dosstub[0x40]; DWORD nt_sig; IMAGE_FILE_HEADER filehdr; -#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64) +#if PTR_SIZE == 8 IMAGE_OPTIONAL_HEADER64 opthdr; #else #ifdef _WIN64 @@ -580,55 +575,17 @@ static void pe_add_coffsym(struct pe_info *pe) /* Run cv2pdb, available at https://github.com/rainers/cv2pdb. It reads and strips the dwarf info and creates a .pdb file instead */ -#ifndef _WIN32 -static void pe_shell_quote(CString *cmd, const char *arg) -{ - cstr_cat(cmd, "'", 1); - while (*arg) { - if (*arg == '\'') - cstr_cat(cmd, "'\\''", 4); - else - cstr_cat(cmd, arg, 1); - ++arg; - } - cstr_cat(cmd, "'", 1); -} -#endif - -static intptr_t pe_run_cv2pdb(const char *exename) -{ -#ifdef _WIN32 - const char *argv[] = { "cv2pdb.exe", exename, NULL }; - return _spawnvp(_P_WAIT, "cv2pdb.exe", argv); -#else - CString cmd; - intptr_t ret; - - cstr_new(&cmd); - cstr_cat(&cmd, "cv2pdb.exe ", -1); - pe_shell_quote(&cmd, exename); - cstr_ccat(&cmd, 0); - ret = system(cmd.data); - cstr_free(&cmd); - return ret; -#endif -} - static void pe_create_pdb(TCCState *s1, const char *exename) { - size_t len = strlen(exename); - char *pdbfile = tcc_malloc(len + sizeof(".pdb")); - intptr_t r; - - strcpy(pdbfile, exename); - strcpy(tcc_fileextension(pdbfile), ".pdb"); - r = pe_run_cv2pdb(exename); + char buf[300]; int r; + snprintf(buf, sizeof buf, "cv2pdb.exe \"%s\"", exename); + r = system(buf); + strcpy(tcc_fileextension(strcpy(buf, exename)), ".pdb"); if (r) { - tcc_error_noabort("could not create '%s'\n(need working cv2pdb from https://github.com/rainers/cv2pdb)", pdbfile); + tcc_error_noabort("could not create '%s'\n(need working cv2pdb from https://github.com/rainers/cv2pdb)", buf); } else if (s1->verbose) { - printf("<- %s\n", pdbfile); + printf("<- %s\n", buf); } - tcc_free(pdbfile); } /*----------------------------------------------------------------------------*/ @@ -674,31 +631,12 @@ static int pe_write(struct pe_info *pe) 0x00000000, /*DWORD TimeDateStamp; */ 0x00000000, /*DWORD PointerToSymbolTable; */ 0x00000000, /*DWORD NumberOfSymbols; */ -#if defined(TCC_TARGET_X86_64) - 0x00F0, /*WORD SizeOfOptionalHeader; */ - 0x022F /*WORD Characteristics; */ -#define CHARACTERISTICS_DLL 0x222E -#elif defined(TCC_TARGET_I386) - 0x00E0, /*WORD SizeOfOptionalHeader; */ - 0x030F /*WORD Characteristics; */ -#define CHARACTERISTICS_DLL 0x230E -#elif defined(TCC_TARGET_ARM) - 0x00E0, /*WORD SizeOfOptionalHeader; */ - 0x010F, /*WORD Characteristics; */ -#define CHARACTERISTICS_DLL 0x230F -#elif defined(TCC_TARGET_ARM64) - 0x00F0, /*WORD SizeOfOptionalHeader; */ - 0x0022 /*WORD Characteristics; */ -#define CHARACTERISTICS_DLL 0x2022 -#endif -},{ + 0x00E0 + (PTR_SIZE-4)*4, /*WORD SizeOfOptionalHeader; */ + CHARACTERISTICS_EXE, /*WORD Characteristics; */ + },{ /* IMAGE_OPTIONAL_HEADER opthdr */ /* Standard fields. */ -#if defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64) - 0x020B, /*WORD Magic; */ -#else - 0x010B, /*WORD Magic; */ -#endif + PE_MAGIC, /*WORD Magic; */ 0x06, /*BYTE MajorLinkerVersion; */ 0x00, /*BYTE MinorLinkerVersion; */ 0x00000000, /*DWORD SizeOfCode; */ @@ -706,45 +644,29 @@ static int pe_write(struct pe_info *pe) 0x00000000, /*DWORD SizeOfUninitializedData; */ 0x00000000, /*DWORD AddressOfEntryPoint; */ 0x00000000, /*DWORD BaseOfCode; */ -#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64) +#if PTR_SIZE == 4 0x00000000, /*DWORD BaseOfData; */ #endif /* NT additional fields. */ -#if defined(TCC_TARGET_ARM) - 0x00100000, /*DWORD ImageBase; */ -#elif defined(TCC_TARGET_ARM64) - 0x140000000ULL, /*ULONGLONG ImageBase; */ -#else - 0x00400000, /*DWORD ImageBase; */ -#endif + 0x00000000, /*ADDR3264 ImageBase; */ 0x00001000, /*DWORD SectionAlignment; */ 0x00000200, /*DWORD FileAlignment; */ -#if defined(TCC_TARGET_ARM64) - 0x0006, /*WORD MajorOperatingSystemVersion; */ - 0x0002, /*WORD MinorOperatingSystemVersion; */ -#else - 0x0004, /*WORD MajorOperatingSystemVersion; */ - 0x0000, /*WORD MinorOperatingSystemVersion; */ -#endif + OS_VER >> 8, /*WORD MajorOperatingSystemVersion; */ + OS_VER & 255, /*WORD MinorOperatingSystemVersion; */ 0x0000, /*WORD MajorImageVersion; */ 0x0000, /*WORD MinorImageVersion; */ -#if defined(TCC_TARGET_ARM64) - 0x0006, /*WORD MajorSubsystemVersion; */ - 0x0002, /*WORD MinorSubsystemVersion; */ -#else - 0x0004, /*WORD MajorSubsystemVersion; */ - 0x0000, /*WORD MinorSubsystemVersion; */ -#endif + OS_VER >> 8, /*WORD MajorSubsystemVersion; */ + OS_VER & 255, /*WORD MinorSubsystemVersion; */ 0x00000000, /*DWORD Win32VersionValue; */ 0x00000000, /*DWORD SizeOfImage; */ 0x00000200, /*DWORD SizeOfHeaders; */ 0x00000000, /*DWORD CheckSum; */ 0x0002, /*WORD Subsystem; */ - 0x0000, /*WORD DllCharacteristics; */ - 0x00100000, /*DWORD SizeOfStackReserve; */ - 0x00001000, /*DWORD SizeOfStackCommit; */ - 0x00100000, /*DWORD SizeOfHeapReserve; */ - 0x00001000, /*DWORD SizeOfHeapCommit; */ + DLLCHARACTERISTICS, /*WORD DllCharacteristics; */ + 0x00100000, /*ADDR3264 SizeOfStackReserve; */ + 0x00001000, /*ADDR3264 SizeOfStackCommit; */ + 0x00100000, /*ADDR3264 SizeOfHeapReserve; */ + 0x00001000, /*ADDR3264 SizeOfHeapCommit; */ 0x00000000, /*DWORD LoaderFlags; */ 0x00000010, /*DWORD NumberOfRvaAndSizes; */ @@ -799,7 +721,7 @@ static int pe_write(struct pe_info *pe) break; case sec_data: -#if !defined(TCC_TARGET_X86_64) && !defined(TCC_TARGET_ARM64) +#if PTR_SIZE == 4 if (!pe_header.opthdr.BaseOfData) pe_header.opthdr.BaseOfData = addr; #endif @@ -861,14 +783,14 @@ static int pe_write(struct pe_info *pe) pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders; pe_header.opthdr.ImageBase = pe->imagebase; pe_header.opthdr.Subsystem = pe->subsystem; - pe_header.opthdr.DllCharacteristics = pe_get_dll_characteristics(s1); + pe_header.opthdr.DllCharacteristics = s1->pe_dll_characteristics; if (s1->pe_stack_size) pe_header.opthdr.SizeOfStackReserve = s1->pe_stack_size; if (PE_DLL == pe->type) pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL; pe_header.filehdr.Characteristics |= s1->pe_characteristics; if (pe->reloc) - pe_header.filehdr.Characteristics &= ~PE_IMAGE_FILE_RELOCS_STRIPPED; + pe_header.filehdr.Characteristics &= ~IMAGE_FILE_RELOCS_STRIPPED; if (pe->coffsym) { pe_add_coffsym(pe); @@ -1291,8 +1213,8 @@ static int pe_assign_addresses (struct pe_info *pe) Section *s; TCCState *s1 = pe->s1; - if (PE_DLL == pe->type || - (pe_get_dll_characteristics(s1) & PE_DLLCHARACTERISTICS_DYNAMIC_BASE)) + if (PE_DLL == pe->type + || (s1->pe_dll_characteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE)) pe->reloc = new_section(s1, ".reloc", SHT_PROGBITS, 0); //pe->thunk = new_section(s1, ".iedat", SHT_PROGBITS, SHF_ALLOC); @@ -1483,14 +1405,10 @@ static int pe_check_symbols(struct pe_info *pe) offset + 8, R_XXX_THUNKFIX, is->iat_index); // offset to IAT position #elif defined(TCC_TARGET_ARM64) p = section_ptr_add(text_section, 24); - /* ldr x16, [pc, #16] */ - write32le(p + 0, 0x58000090); - /* ldr x16, [x16] */ - write32le(p + 4, 0xf9400210); - /* br x16 */ - write32le(p + 8, 0xd61f0200); - /* nop for 8-byte literal alignment */ - write32le(p + 12, 0xd503201f); + write32le(p + 0, 0x58000090); /* ldr x16, [pc, #16] */ + write32le(p + 4, 0xf9400210); /* ldr x16, [x16] */ + write32le(p + 8, 0xd61f0200); /* br x16 */ + write32le(p + 12, 0xd503201f); /* nop for alignment */ put_elf_reloc(symtab_section, text_section, offset + 16, R_XXX_THUNKFIX, is->iat_index); #else @@ -1716,7 +1634,7 @@ static int get_dllexports(int fd, char **pp) if (!read_mem(fd, pef_hdroffset, &ih, sizeof ih)) goto the_end; opt_hdroffset = pef_hdroffset + sizeof ih; - if (ih.Machine == 0x014C) { + if (ih.Machine == 0x014C || ih.Machine == 0x01C0) { IMAGE_OPTIONAL_HEADER32 oh; sec_hdroffset = opt_hdroffset + sizeof oh; if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh)) @@ -1724,7 +1642,7 @@ static int get_dllexports(int fd, char **pp) if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes) goto the_end_0; addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; - } else if (ih.Machine == 0x8664 || ih.Machine == IMAGE_FILE_MACHINE_ARM64) { + } else if (ih.Machine == 0x8664 || ih.Machine == 0xAA64) { IMAGE_OPTIONAL_HEADER64 oh; sec_hdroffset = opt_hdroffset + sizeof oh; if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh)) @@ -2209,19 +2127,9 @@ static void pe_set_options(TCCState * s1, struct pe_info *pe) { if (PE_DLL == pe->type) { /* XXX: check if is correct for arm-pe target */ -#if defined(TCC_TARGET_ARM64) - pe->imagebase = 0x180000000ULL; -#else - pe->imagebase = 0x10000000; -#endif + pe->imagebase = IMAGE_BASE_DLL; } else { -#if defined(TCC_TARGET_ARM) - pe->imagebase = 0x00010000; -#elif defined(TCC_TARGET_ARM64) - pe->imagebase = 0x140000000ULL; -#else - pe->imagebase = 0x00400000; -#endif + pe->imagebase = IMAGE_BASE_EXE; } #if defined(TCC_TARGET_ARM) diff --git a/tccrun.c b/tccrun.c index b3127413..4ff511df 100644 --- a/tccrun.c +++ b/tccrun.c @@ -108,6 +108,11 @@ static void win64_del_function_table(void *); //#define CONFIG_SELINUX 1 #endif +/* use VirtualAlloc() instead of tcc_malloc() */ +#if defined _WIN32 && !defined CONFIG_RUNMEM_VIRTUALALLOC +# define CONFIG_RUNMEM_VIRTUALALLOC 1 +#endif + static int rt_mem(TCCState *s1, int size) { void *ptr; @@ -129,16 +134,14 @@ static int rt_mem(TCCState *s1, int size) ptr_diff = (char*)prw - (char*)ptr; /* = size; */ //printf("map %p %p %p\n", ptr, prw, (void*)ptr_diff); size *= 2; -#else -# ifdef _WIN32 - /* Generated code is page-protected below; avoid changing CRT heap pages. */ +#elif CONFIG_RUNMEM_VIRTUALALLOC + /* always page-aligned */ ptr = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); -# else - ptr = tcc_malloc(size += PAGESIZE); /* one extra page to align malloc memory */ -# endif -#endif if (!ptr) return tcc_error_noabort("tccrun: could not allocate memory"); +#else + ptr = tcc_malloc(size += PAGESIZE); /* one extra page to align malloc memory */ +#endif s1->run_ptr = ptr; s1->run_size = size; return ptr_diff; @@ -191,24 +194,18 @@ ST_FUNC void tcc_run_free(TCCState *s1) if (NULL == ptr) return; st_unlink(s1); +#ifdef _WIN64 + win64_del_function_table(s1->run_function_table); +#endif size = s1->run_size; #ifdef CONFIG_SELINUX munmap(ptr, size); +#elif CONFIG_RUNMEM_VIRTUALALLOC + VirtualFree(ptr, size, MEM_RELEASE); #else -# ifdef _WIN32 - (void)size; -# ifdef _WIN64 - win64_del_function_table(s1->run_function_table); -# endif - VirtualFree(ptr, 0, MEM_RELEASE); -# else /* unprotect memory to make it usable for malloc again */ protect_pages((void*)PAGEALIGN(ptr), size - PAGESIZE, 2 /*rw*/); -# ifdef _WIN64 - win64_del_function_table(s1->run_function_table); -# endif tcc_free(ptr); -# endif #endif } @@ -312,7 +309,7 @@ static void cleanup_sections(TCCState *s1) } /* ------------------------------------------------------------- */ -/* 0 = .text rwx other rw (memory >= 2 pages a 4096 bytes) */ +/* 0 = .text rwx other rwx (memory >= 2 pages a 4096 bytes) */ /* 1 = .text rx other rw (memory >= 3 pages) */ /* 2 = .text rx .rdata ro .data/.bss rw (memory >= 4 pages) */ @@ -506,14 +503,11 @@ static void *win64_add_function_table(TCCState *s1) void *p = NULL; if (s1->uw_pdata) { p = (void*)s1->uw_pdata->sh_addr; - if (!RtlAddFunctionTable( + RtlAddFunctionTable( (RUNTIME_FUNCTION*)p, s1->uw_pdata->data_offset / sizeof (RUNTIME_FUNCTION), s1->pe_imagebase - )) { - tcc_error_noabort("RtlAddFunctionTable failed"); - p = NULL; - } + ); s1->uw_pdata = NULL; } return p; diff --git a/tests/tests2/Makefile b/tests/tests2/Makefile index c502b7c8..f71cc904 100644 --- a/tests/tests2/Makefile +++ b/tests/tests2/Makefile @@ -19,9 +19,6 @@ ifeq (,$(filter i386 x86_64,$(ARCH))) SKIP += 85_asm-outside-function.test # x86 asm SKIP += 127_asm_goto.test # hardcodes x86 asm endif -ifeq (,$(filter x86_64 riscv64 arm64 i386,$(ARCH))) - SKIP += 144_tls.test # TLS only implemented on these architectures so far -endif ifeq ($(CONFIG_backtrace),no) SKIP += 113_btdll.test CONFIG_bcheck = no @@ -57,22 +54,23 @@ ifneq (,$(filter OpenBSD FreeBSD NetBSD,$(TARGETOS))) SKIP += 114_bound_signal.test # libc problem signal/fork SKIP += 116_bound_setjmp2.test # No TLS_FUNC/TLS_VAR in bcheck.c endif -ifdef CONFIG_OSX +ifeq ($(CONFIG_OSX),yes) SKIP += 144_tls.test # TLS runtime not supported on Mach-O endif -ifeq (,$(filter arm64 aarch64,$(ARCH))) +ifeq (,$(filter i386 x86_64 riscv64 arm64,$(ARCH))) + SKIP += 144_tls.test # TLS only implemented on these architectures so far +endif +ifneq (-$(ARCH)-,-arm64-) SKIP += 138_arm64_encoding.test SKIP += 139_arm64_errors.test SKIP += 140_arm64_extasm.test endif -ifneq ($(CONFIG_WIN32),yes) - SKIP += 145_winarm64_interlocked.test -else ifeq (,$(filter arm64 aarch64,$(ARCH))) - SKIP += 145_winarm64_interlocked.test -endif -ifeq (,$(filter riscv64,$(ARCH))) +ifneq (-$(ARCH)-,-riscv64-) SKIP += 141_riscv_asm.test # riscv64 asm endif +ifneq (-$(ARCH)-$(CONFIG_WIN32)-,-arm64-yes-) + SKIP += 145_winarm64_interlocked.test +endif # Some tests might need arguments ARGS =