From 7e839e6962b40e1b2cee1d57830517465f8abb3f Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Sat, 23 Mar 2024 20:18:28 +0100 Subject: [PATCH] all: more cleanups; NFCI --- .clang-tidy | 2 +- .clangd | 3 +- .editorconfig | 4 +- .github/workflows/ci.yml | 6 +- Makefile | 12 ++- misc/make/Makefile-extra.mk | 37 ++++++--- src/Makefile | 29 +++---- src/check/dt_impl.cpp | 28 +------ src/p_w32pe_i386.cpp | 3 +- src/p_wince_arm.cpp | 2 +- src/pefile.cpp | 159 +++++++++++++++++++----------------- src/pefile.h | 22 ++--- src/util/cxxlib.h | 7 ++ src/util/system_features.h | 61 ++++++++++++++ src/util/system_headers.h | 1 + 15 files changed, 220 insertions(+), 156 deletions(-) create mode 100644 src/util/system_features.h diff --git a/.clang-tidy b/.clang-tidy index 84d6398b..5822cd87 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,6 +1,6 @@ # vim:set ft=yaml ts=2 sw=2 et: # Copyright (C) Markus Franz Xaver Johannes Oberhumer -# for clang-tidy-16 from https://clang.llvm.org/extra/clang-tidy/ +# for clang-tidy from https://clang.llvm.org/extra/clang-tidy/ --- Checks: > -*, diff --git a/.clangd b/.clangd index c96b58dd..a585e8cd 100644 --- a/.clangd +++ b/.clangd @@ -1,6 +1,6 @@ # vim:set ft=yaml ts=2 sw=2 et: # Copyright (C) Markus Franz Xaver Johannes Oberhumer -# for clangd-17 from https://clangd.llvm.org/ +# for clangd from https://clangd.llvm.org/ --- # treat *.h files as C++ source code If: @@ -17,6 +17,7 @@ If: CompileFlags: Add: - -std=gnu++17 + # -std=gnu++20 # requires clang >= 10.0 --- # common flags for all C/C++ files If: diff --git a/.editorconfig b/.editorconfig index 3786de05..8dff0098 100644 --- a/.editorconfig +++ b/.editorconfig @@ -15,8 +15,8 @@ trim_trailing_whitespace = true indent_size = 8 indent_style = tab -[*.S] +[{*.asm,*.S}] indent_size = 8 -[*.yml] +[{*.yaml,*.yml}] indent_size = 2 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c2892330..88b97bc9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,8 +16,8 @@ env: UPX_CMAKE_BUILD_FLAGS: --verbose UPX_CMAKE_CONFIG_FLAGS: -Wdev --warn-uninitialized UPX_DEBUG_TEST_FLOAT_DIVISION_BY_ZERO: 1 - # 2024-03-16 - ZIG_DIST_VERSION: 0.12.0-dev.3322+a4508ad71 + # 2024-03-23 + ZIG_DIST_VERSION: 0.12.0-dev.3429+13a9d94a8 jobs: job-rebuild-and-verify-stubs: @@ -473,7 +473,7 @@ jobs: - { zig_target: i386-linux-musl, qemu: qemu-i386 -cpu Conroe } # { zig_target: i386-linux-musl, qemu: qemu-i386 -cpu Conroe, zig_pic: -fPIE } - { zig_target: i386-windows-gnu } - # mips and mipsel: bad hard-float code generation; see https://github.com/upx/upx/issues/788 + # mips and mipsel: bad hard-float code generation(??); or QEMU bug; or UPX bug; see https://github.com/upx/upx/issues/788 - { zig_target: mips-linux-musl, zig_flags: -msoft-float, qemu: qemu-mips } - { zig_target: mipsel-linux-musl, zig_flags: -msoft-float, qemu: qemu-mipsel } - { zig_target: powerpc-linux-musl, qemu: qemu-ppc } diff --git a/Makefile b/Makefile index 3b3f3b69..54d92609 100644 --- a/Makefile +++ b/Makefile @@ -46,10 +46,10 @@ build/release: PHONY .SUFFIXES: # shortcuts (all => debug + release) -debug: build/debug -release: build/release -all build/all: build/debug build/release -build/%/all: $$(dir $$@)debug $$(dir $$@)release ; +debug: build/debug PHONY +release: build/release PHONY +all build/all: build/debug build/release PHONY +build/%/all: $$(dir $$@)debug $$(dir $$@)release PHONY; # # END of Makefile @@ -63,9 +63,7 @@ include ./misc/make/Makefile-extra.mk endif # developer convenience -CTEST = ctest -test:: $(.DEFAULT_GOAL) PHONY - cd $(.DEFAULT_GOAL) && $(CTEST) +test:: build/all+test PHONY ifneq ($(wildcard /usr/bin/env),) # need Unix utils like bash, perl, sed, xargs, etc. ifneq ($(wildcard ./misc/scripts/.),) check-whitespace clang-format run-testsuite run-testsuite-debug run-testsuite-release: src/Makefile PHONY diff --git a/misc/make/Makefile-extra.mk b/misc/make/Makefile-extra.mk index 4fe8814a..78c23de6 100644 --- a/misc/make/Makefile-extra.mk +++ b/misc/make/Makefile-extra.mk @@ -11,6 +11,23 @@ override check_undefined = $(foreach 1,$1,$(if $(filter undefined,$(origin $1)), $(call check_defined,run_config run_build) $(call check_undefined,run_config_and_build) +#*********************************************************************** +# build and test +#*********************************************************************** + +CTEST = ctest + +build/debug+test: $$(dir $$@)debug PHONY; cd "$(dir $@)debug" && $(CTEST) +build/%/debug+test: $$(dir $$@)debug PHONY; cd "$(dir $@)debug" && $(CTEST) +build/release+test: $$(dir $$@)release PHONY; cd "$(dir $@)release" && $(CTEST) +build/%/release+test: $$(dir $$@)release PHONY; cd "$(dir $@)release" && $(CTEST) +build/%/all+test: $$(dir $$@)debug+test $$(dir $$@)release+test PHONY ; + +# shortcuts +debug+test: build/debug+test PHONY +release+test: build/release+test PHONY +all+test build/all+test: build/debug+test build/release+test PHONY + #*********************************************************************** # extra builds: some pre-defined build configurations #*********************************************************************** @@ -29,43 +46,43 @@ build/extra/clang/%: export CXX = clang++ # force building with clang/clang++ -m32 build/extra/clang-m32/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/clang-m32/release: PHONY; $(call run_config_and_build,$@,Release) -build/extra/clang-m32/%: export CC = clang -m32 +build/extra/clang-m32/%: export CC = clang -m32 build/extra/clang-m32/%: export CXX = clang++ -m32 # force building with clang/clang++ -mx32 build/extra/clang-mx32/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/clang-mx32/release: PHONY; $(call run_config_and_build,$@,Release) -build/extra/clang-mx32/%: export CC = clang -mx32 +build/extra/clang-mx32/%: export CC = clang -mx32 build/extra/clang-mx32/%: export CXX = clang++ -mx32 # force building with clang/clang++ -m64 build/extra/clang-m64/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/clang-m64/release: PHONY; $(call run_config_and_build,$@,Release) -build/extra/clang-m64/%: export CC = clang -m64 +build/extra/clang-m64/%: export CC = clang -m64 build/extra/clang-m64/%: export CXX = clang++ -m64 # force building with clang/clang++ -static build/extra/clang-static/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/clang-static/release: PHONY; $(call run_config_and_build,$@,Release) -build/extra/clang-static/%: export CC = clang -static +build/extra/clang-static/%: export CC = clang -static build/extra/clang-static/%: export CXX = clang++ -static # force building with clang/clang++ -static-pie build/extra/clang-static-pie/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/clang-static-pie/release: PHONY; $(call run_config_and_build,$@,Release) -build/extra/clang-static-pie/%: export CC = clang -static-pie -fPIE -Wno-unused-command-line-argument +build/extra/clang-static-pie/%: export CC = clang -static-pie -fPIE -Wno-unused-command-line-argument build/extra/clang-static-pie/%: export CXX = clang++ -static-pie -fPIE -Wno-unused-command-line-argument # force building with clang/clang++ -static -flto build/extra/clang-static-lto/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/clang-static-lto/release: PHONY; $(call run_config_and_build,$@,Release) -build/extra/clang-static-lto/%: export CC = clang -static -flto +build/extra/clang-static-lto/%: export CC = clang -static -flto build/extra/clang-static-lto/%: export CXX = clang++ -static -flto # force building with clang/clang++ C17/C++20 build/extra/clang-std-cxx20/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/clang-std-cxx20/release: PHONY; $(call run_config_and_build,$@,Release) -build/extra/clang-std-cxx20/%: export CC = clang -std=gnu17 +build/extra/clang-std-cxx20/%: export CC = clang -std=gnu17 build/extra/clang-std-cxx20/%: export CXX = clang++ -std=gnu++20 build/extra/clang-std-cxx20/%: export UPX_CONFIG_DISABLE_C_STANDARD=ON build/extra/clang-std-cxx20/%: export UPX_CONFIG_DISABLE_CXX_STANDARD=ON @@ -73,7 +90,7 @@ build/extra/clang-std-cxx20/%: export UPX_CONFIG_DISABLE_CXX_STANDARD=ON # force building with clang/clang++ C23/C++23 build/extra/clang-std-cxx23/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/clang-std-cxx23/release: PHONY; $(call run_config_and_build,$@,Release) -build/extra/clang-std-cxx23/%: export CC = clang -std=gnu2x +build/extra/clang-std-cxx23/%: export CC = clang -std=gnu2x build/extra/clang-std-cxx23/%: export CXX = clang++ -std=gnu++2b build/extra/clang-std-cxx23/%: export UPX_CONFIG_DISABLE_C_STANDARD=ON build/extra/clang-std-cxx23/%: export UPX_CONFIG_DISABLE_CXX_STANDARD=ON @@ -173,7 +190,7 @@ build/extra/cross-windows-mingw64/%: CMAKE_CROSSCOMPILING_EMULATOR ?= wine64 # cross compiler: macOS arm64 (aarch64) build/extra/cross-darwin-arm64/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/cross-darwin-arm64/release: PHONY; $(call run_config_and_build,$@,Release) -build/extra/cross-darwin-arm64/%: export CC = clang -target arm64-apple-darwin +build/extra/cross-darwin-arm64/%: export CC = clang -target arm64-apple-darwin build/extra/cross-darwin-arm64/%: export CXX = clang++ -target arm64-apple-darwin build/extra/cross-darwin-arm64/%: CMAKE_SYSTEM_NAME ?= Darwin build/extra/cross-darwin-arm64/%: CMAKE_SYSTEM_PROCESSOR ?= arm64 @@ -181,7 +198,7 @@ build/extra/cross-darwin-arm64/%: CMAKE_SYSTEM_PROCESSOR ?= arm64 # cross compiler: macOS x86_64 (amd64) build/extra/cross-darwin-x86_64/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/cross-darwin-x86_64/release: PHONY; $(call run_config_and_build,$@,Release) -build/extra/cross-darwin-x86_64/%: export CC = clang -target x86_64-apple-darwin +build/extra/cross-darwin-x86_64/%: export CC = clang -target x86_64-apple-darwin build/extra/cross-darwin-x86_64/%: export CXX = clang++ -target x86_64-apple-darwin build/extra/cross-darwin-x86_64/%: CMAKE_SYSTEM_NAME ?= Darwin build/extra/cross-darwin-x86_64/%: CMAKE_SYSTEM_PROCESSOR ?= x86_64 diff --git a/src/Makefile b/src/Makefile index 6d7fb11f..a8eb0541 100644 --- a/src/Makefile +++ b/src/Makefile @@ -20,27 +20,22 @@ endif # NOTE that the top-level Makefile .DEFAULT_GOAL is build/release .DEFAULT_GOAL = build/all -build/debug: $(top_srcdir)/build/debug -build/release: $(top_srcdir)/build/release - .NOTPARALLEL: # because the actual builds use "cmake --parallel" .PHONY: PHONY .SECONDEXPANSION: .SUFFIXES: -# shortcuts (all => debug + release) -debug: build/debug -release: build/release -all build/all: build/debug build/release +build/debug build/release build/all: PHONY; $(MAKE) -C $(top_srcdir) $@ +build/debug+test build/release+test build/all+test: PHONY; $(MAKE) -C $(top_srcdir) $@ +# shortcuts +debug release all: PHONY; $(MAKE) -C $(top_srcdir) $@ +debug+test release+test all+test: PHONY; $(MAKE) -C $(top_srcdir) $@ -# actual rules - redirect to top-level -$(top_srcdir)/build/debug: PHONY; $(MAKE) -C $(top_srcdir) build/debug -$(top_srcdir)/build/release: PHONY; $(MAKE) -C $(top_srcdir) build/release +test:: build/all+test PHONY -# convenience -CTEST = ctest -test:: $(top_srcdir)/build/debug PHONY; cd $< && $(CTEST) -test:: $(top_srcdir)/build/release PHONY; cd $< && $(CTEST) +# OLD names [deprecated] +$(top_srcdir)/build/debug: build/debug PHONY +$(top_srcdir)/build/release: build/release PHONY #*********************************************************************** # make run-testsuite @@ -65,15 +60,15 @@ endif # The actual (new) checksums are in ./tmp-upx-testsuite-*/testsuite_1/.sha256sums.recreate ifneq ($(wildcard $(upx_testsuite_SRCDIR)/files/packed/.),) ifneq ($(wildcard $(top_srcdir)/misc/testsuite/upx_testsuite_1.sh),) -run-testsuite: run-testsuite-release +run-testsuite: run-testsuite-release PHONY run-testsuite-%: export upx_testsuite_SRCDIR := $(upx_testsuite_SRCDIR) run-testsuite-debug: export upx_testsuite_BUILDDIR := ./tmp-upx-testsuite-debug run-testsuite-debug: export upx_exe := $(top_srcdir)/build/debug/upx -run-testsuite-debug: $(top_srcdir)/build/debug PHONY +run-testsuite-debug: build/debug PHONY time -p bash $(top_srcdir)/misc/testsuite/upx_testsuite_1.sh run-testsuite-release: export upx_testsuite_BUILDDIR := ./tmp-upx-testsuite-release run-testsuite-release: export upx_exe := $(top_srcdir)/build/release/upx -run-testsuite-release: $(top_srcdir)/build/release PHONY +run-testsuite-release: build/release PHONY time -p bash $(top_srcdir)/misc/testsuite/upx_testsuite_1.sh endif endif diff --git a/src/check/dt_impl.cpp b/src/check/dt_impl.cpp index 1e2a2881..d89289c0 100644 --- a/src/check/dt_impl.cpp +++ b/src/check/dt_impl.cpp @@ -25,38 +25,12 @@ */ #include "../util/system_defs.h" +#include "../util/system_features.h" /************************************************************************* // doctest support code implementation **************************************************************************/ -#if 0 // TODO later -// libc++ hardenining -#if defined(__clang__) && defined(__clang_major__) && (__clang_major__ + 0 >= 18) -#if DEBUG -#define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_DEBUG -#else -#define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_EXTENSIVE -#endif -#endif -#if defined(__clang__) && defined(__clang_major__) && (__clang_major__ + 0 < 18) -#if DEBUG -#define _LIBCPP_ENABLE_ASSERTIONS 1 -#endif -#endif -#endif // TODO later - -#if defined(__has_include) -#if __has_include() -#include // for __GLIBC__ -#endif -#endif -// aligned_alloc() was added in glibc-2.16 -#if defined(__ELF__) && defined(__GLIBC__) && defined(__GLIBC_MINOR__) && (__GLIBC__ + 0 == 2) && \ - (__GLIBC_MINOR__ + 0 < 16) -#define _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION -#endif - #define DOCTEST_CONFIG_IMPLEMENT #define DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS diff --git a/src/p_w32pe_i386.cpp b/src/p_w32pe_i386.cpp index 3d37104f..72e5a07a 100644 --- a/src/p_w32pe_i386.cpp +++ b/src/p_w32pe_i386.cpp @@ -235,7 +235,8 @@ void PackW32PeI386::defineSymbols(unsigned ncsection, unsigned upxsection, unsig void PackW32PeI386::addNewRelocations(Reloc &rel, unsigned upxsection) { if (use_stub_relocs) - rel.add(upxsection + linker->getSymbolOffset("PESOCREL") + 1, 3); + rel.add_reloc(upxsection + linker->getSymbolOffset("PESOCREL") + 1, + IMAGE_REL_BASED_HIGHLOW); } void PackW32PeI386::setOhDataBase(const pe_section_t *osection) { oh.database = osection[2].vaddr; } diff --git a/src/p_wince_arm.cpp b/src/p_wince_arm.cpp index ea707735..19550c40 100644 --- a/src/p_wince_arm.cpp +++ b/src/p_wince_arm.cpp @@ -190,7 +190,7 @@ void PackWinCeArm::addNewRelocations(Reloc &rel, unsigned upxsection) { for (unsigned s2r = 0; s2r < TABLESIZE(symbols_to_relocate); s2r++) { unsigned off = linker->getSymbolOffset(symbols_to_relocate[s2r]); if (off != 0xdeaddead) - rel.add(off + upxsection, 3); + rel.add_reloc(off + upxsection, IMAGE_REL_BASED_HIGHLOW); } } diff --git a/src/pefile.cpp b/src/pefile.cpp index 7c4e4c91..4497b893 100644 --- a/src/pefile.cpp +++ b/src/pefile.cpp @@ -213,18 +213,10 @@ int PeFile::readFileHeader() { // interval handling **************************************************************************/ -PeFile::Interval::Interval(void *b) : capacity(0), base(b), ivarr(nullptr), ivnum(0) {} +PeFile::Interval::Interval(SPAN_P(byte) b) : base(b) {} PeFile::Interval::~Interval() noexcept { free(ivarr); } -void PeFile::Interval::add(const void *start, unsigned len) { - add(ptr_diff_bytes(start, base), len); -} - -void PeFile::Interval::add(const void *start, const void *end) { - add(ptr_diff_bytes(start, base), ptr_diff_bytes(end, start)); -} - int __acc_cdecl_qsort PeFile::Interval::compare(const void *p1, const void *p2) { const interval *i1 = (const interval *) p1; const interval *i2 = (const interval *) p2; @@ -239,16 +231,28 @@ int __acc_cdecl_qsort PeFile::Interval::compare(const void *p1, const void *p2) return 0; } -void PeFile::Interval::add(unsigned start, unsigned len) { - if (ivnum == capacity) - ivarr = (interval *) realloc(ivarr, (capacity += 15) * sizeof(interval)); +void PeFile::Interval::add_interval(unsigned start, unsigned len) { + if (ivnum == ivcapacity) { + ivcapacity += 15; + ivarr = (interval *) realloc(ivarr, mem_size(sizeof(interval), ivcapacity)); + assert(ivarr != nullptr); + } ivarr[ivnum].start = start; - ivarr[ivnum++].len = len; + ivarr[ivnum].len = len; + ivnum += 1; } -void PeFile::Interval::add(const Interval *iv) { - for (unsigned ic = 0; ic < iv->ivnum; ic++) - add(iv->ivarr[ic].start, iv->ivarr[ic].len); +void PeFile::Interval::add_interval(const void *start, unsigned len) { + add_interval(ptr_udiff_bytes(start, base), len); +} + +void PeFile::Interval::add_interval(const void *start, const void *end) { + add_interval(ptr_udiff_bytes(start, base), ptr_udiff_bytes(end, start)); +} + +void PeFile::Interval::add_interval(const Interval *other) { + for (unsigned ic = 0; ic < other->ivnum; ic++) + add_interval(other->ivarr[ic].start, other->ivarr[ic].len); } void PeFile::Interval::flatten() { @@ -269,7 +273,7 @@ void PeFile::Interval::flatten() { void PeFile::Interval::clear() { for (unsigned ic = 0; ic < ivnum; ic++) - memset((char *) base + ivarr[ic].start, 0, ivarr[ic].len); + memset(base + ivarr[ic].start, 0, ivarr[ic].len); } void PeFile::Interval::dump() const { @@ -293,7 +297,7 @@ static constexpr size_t RELOC_INPLACE_OFFSET = 64 * 1024; static constexpr size_t RELOC_ENTRY_SIZE = 5; // encoded size in bytes; actual encoding is private static void reloc_entry_encode(SPAN_P(byte) buf, unsigned pos, unsigned reloc_type) { - if (reloc_type >= 16) + if (reloc_type == 0 || reloc_type >= 16) throwCantPack("bad reloc_type %u %u", pos, reloc_type); set_ne32(buf, pos); buf[4] = (upx_uint8_t) reloc_type; @@ -301,6 +305,7 @@ static void reloc_entry_encode(SPAN_P(byte) buf, unsigned pos, unsigned reloc_ty static void reloc_entry_decode(SPAN_P(const byte) buf, unsigned *pos, unsigned *reloc_type) { *pos = get_ne32(buf); *reloc_type = buf[4]; + assert(*reloc_type > 0 && *reloc_type < 16); } static int __acc_cdecl_qsort reloc_entry_compare(const void *a, const void *b) { const unsigned pos1 = get_ne32(a); @@ -322,9 +327,10 @@ PeFile::Reloc::~Reloc() noexcept { } // constructor for compression only -PeFile::Reloc::Reloc(byte *ptr, unsigned bytes) : start(ptr) { +PeFile::Reloc::Reloc(byte *ptr, unsigned bytes) { assert(opt->cmd == CMD_COMPRESS); start_size_in_bytes = mem_size(1, bytes); + start = ptr; initSpans(); // fill counts unsigned pos, reloc_type; @@ -346,7 +352,7 @@ void PeFile::Reloc::initSpans() { rb.reset(); } -// check values so that we have better error messages (instead of getting a cryptic SPAN failure) +// explicitly check values so that we get better error messages (instead of a cryptic SPAN failure) bool PeFile::Reloc::readFromRelocationBlock(byte *next_rb) { // set rb assert(!start_did_alloc); const unsigned off = ptr_udiff_bytes(next_rb, start); @@ -399,8 +405,10 @@ bool PeFile::Reloc::next(unsigned &result_pos, unsigned &result_type) { } } -void PeFile::Reloc::add(unsigned pos, unsigned reloc_type) { +void PeFile::Reloc::add_reloc(unsigned pos, unsigned reloc_type) { assert(start_did_alloc); + if (reloc_type == IMAGE_REL_BASED_IGNORE) + return; auto entry_ptr = start_buf + (RELOC_INPLACE_OFFSET + RELOC_ENTRY_SIZE * counts[0]); reloc_entry_encode(entry_ptr, pos, reloc_type); counts[0] += 1; @@ -436,11 +444,11 @@ void PeFile::Reloc::finish(byte *(&result_ptr), unsigned &result_size) { throwCantPack("duplicate relocs (try --force)"); prev_pos = pos; if (ic == 0 || pos - current_page >= 0x1000) { + current_page = pos & ~0xfff; // page start // prepare next block for writing byte *next_rb = (rb.rel == nullptr) ? start : finish_block(rb.rel); rb.rel = (BaseReloc *) next_rb; rb.rel1 = (LE16 *) (next_rb + 8); - current_page = pos & ~0xfff; // page start rb.rel->virtual_address = current_page; rb.rel->size_of_block = 8; } @@ -449,7 +457,7 @@ void PeFile::Reloc::finish(byte *(&result_ptr), unsigned &result_size) { // info: if this is indeed a valid file we must increase RELOC_INPLACE_OFFSET throwCantPack("too many inplace relocs"); } - // write entry + // write IMAGE_BASE_RELOCATION relocation *rb.rel1++ = (reloc_type << 12) | (pos & 0xfff); rb.rel->size_of_block += 2; } @@ -747,7 +755,7 @@ class PeFile::ImportLinker final : public ElfLinkerAMD64 { unsigned thunk_size; // 4 or 8 bytes - void add(const char *dll, const char *proc, unsigned ordinal) { + void add_import(const char *dll, const char *proc, unsigned ordinal) { TStr sdll(name_for_dll(dll, dll_name_id)); TStr desc_name(name_for_dll(dll, descriptor_id)); @@ -826,20 +834,20 @@ public: } template - void add(const C *dll, unsigned ordinal) { + void add_import(const C *dll, unsigned ordinal) { ACC_COMPILE_TIME_ASSERT(sizeof(C) == 1) // "char" or "byte" assert(ordinal < 0x10000); char ord[1 + 5 + 1]; upx_safe_snprintf(ord, sizeof(ord), "%c%05u", ordinal_id, ordinal); - add((const char *) dll, ordinal ? ord : nullptr, ordinal); + add_import((const char *) dll, ordinal ? ord : nullptr, ordinal); } template - void add(const C1 *dll, const C2 *proc) { + void add_import(const C1 *dll, const C2 *proc) { ACC_COMPILE_TIME_ASSERT(sizeof(C1) == 1) // "char" or "byte" ACC_COMPILE_TIME_ASSERT(sizeof(C2) == 1) // "char" or "byte" assert(proc); - add((const char *) dll, (const char *) proc, 0); + add_import((const char *) dll, (const char *) proc, 0); } unsigned build() { @@ -910,7 +918,7 @@ public: }; /*static*/ const char PeFile::ImportLinker::zeros[sizeof(import_desc)] = {0}; -void PeFile::addKernelImport(const char *name) { ilinker->add(kernelDll(), name); } +void PeFile::addKernelImport(const char *name) { ilinker->add_import(kernelDll(), name); } void PeFile::addStubImports() { addKernelImport("LoadLibraryA"); @@ -1055,14 +1063,14 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1 if (idlls[ic]->ordinal) for (const LEXX *tarr = idlls[ic]->lookupt; *tarr; tarr++) if (*tarr & ord_mask) { - ilinker->add(kernelDll(), *tarr & 0xffff); + ilinker->add_import(kernelDll(), *tarr & 0xffff); kernel32ordinal = true; } } else if (!ilinker->hasDll(idlls[ic]->name)) { if (idlls[ic]->shname && !idlls[ic]->ordinal) - ilinker->add(idlls[ic]->name, idlls[ic]->shname); + ilinker->add_import(idlls[ic]->name, idlls[ic]->shname); else - ilinker->add(idlls[ic]->name, idlls[ic]->ordinal); + ilinker->add_import(idlls[ic]->name, idlls[ic]->ordinal); } } @@ -1095,19 +1103,19 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1 const unsigned take2 = 1 + strlen(ibuf.subref("bad import name %#x", skip2, 1)); memcpy(ppi, ibuf.subref("bad import name %#x", skip2, take2), take2); ppi += take2; - names.add(*tarr, 2 + take2); + names.add_interval(*tarr, 2 + take2); } ppi++; const unsigned esize = ptr_udiff_bytes(tarr, idlls[ic]->lookupt); - lookups.add(idlls[ic]->lookupt, esize); + lookups.add_interval(idlls[ic]->lookupt, esize); if (ptr_diff_bytes(ibuf.subref("bad import name %#x", idlls[ic]->iat, 1), idlls[ic]->lookupt) != 0) { memcpy(ibuf.subref("bad import name %#x", idlls[ic]->iat, esize), idlls[ic]->lookupt, esize); - iats.add(idlls[ic]->iat, esize); + iats.add_interval(idlls[ic]->iat, esize); } - names.add(idlls[ic]->name, strlen(idlls[ic]->name) + 1 + 1); + names.add_interval(idlls[ic]->name, strlen(idlls[ic]->name) + 1 + 1); } ppi += 4; assert(ppi < oimport + soimport); @@ -1137,15 +1145,15 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1 im->dllname = ptr_udiff_bytes(dlls[idlls[ic]->original_position].name, ibuf); } } else { - iats.add(im_start, sizeof(import_desc) * dllnum); + iats.add_interval(im_start, sizeof(import_desc) * dllnum); // zero unneeded data iats.clear(); lookups.clear(); } names.clear(); - iats.add(&names); - iats.add(&lookups); + iats.add_interval(&names); + iats.add_interval(&lookups); iats.flatten(); for (unsigned ic = 0; ic < iats.ivnum; ic++) ilen += iats.ivarr[ic].len; @@ -1158,7 +1166,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1 // export handling **************************************************************************/ -PeFile::Export::Export(char *_base) : base(_base), iv(_base) { +PeFile::Export::Export(char *_base) : base(_base), iv((byte *) _base) { COMPILE_TIME_ASSERT(sizeof(export_dir_t) == 40) COMPILE_TIME_ASSERT_ALIGNED1(export_dir_t) ename = functionptrs = ordinals = nullptr; @@ -1183,7 +1191,7 @@ PeFile::Export::~Export() noexcept { void PeFile::Export::convert(unsigned eoffs, unsigned esize) { memcpy(&edir, base + eoffs, sizeof(export_dir_t)); size = sizeof(export_dir_t); - iv.add(eoffs, size); + iv.add_interval(eoffs, size); if (!edir.name || eoffs + esize <= (unsigned) edir.name) { char msg[50]; @@ -1193,13 +1201,13 @@ void PeFile::Export::convert(unsigned eoffs, unsigned esize) { unsigned len = strlen(base + edir.name) + 1; ename = strdup(base + edir.name); size += len; - iv.add(edir.name, len); + iv.add_interval(edir.name, len); len = 4 * edir.functions; functionptrs = New(char, len + 1); memcpy(functionptrs, base + edir.addrtable, len); size += len; - iv.add(edir.addrtable, len); + iv.add_interval(edir.addrtable, len); unsigned ic; names = New(char *, edir.names + edir.functions + 1); @@ -1208,9 +1216,9 @@ void PeFile::Export::convert(unsigned eoffs, unsigned esize) { len = strlen(n) + 1; names[ic] = strdup(n); size += len; - iv.add(get_le32(base + edir.nameptrtable + ic * 4), len); + iv.add_interval(get_le32(base + edir.nameptrtable + ic * 4), len); } - iv.add(edir.nameptrtable, 4 * edir.names); + iv.add_interval(edir.nameptrtable, 4 * edir.names); size += 4 * edir.names; LE32 *fp = (LE32 *) functionptrs; @@ -1219,7 +1227,7 @@ void PeFile::Export::convert(unsigned eoffs, unsigned esize) { if (fp[ic] >= eoffs && fp[ic] < eoffs + esize) { char *forw = base + fp[ic]; len = strlen(forw) + 1; - iv.add(forw, len); + iv.add_interval(forw, len); size += len; names[ic + edir.names] = strdup(forw); } else @@ -1229,7 +1237,7 @@ void PeFile::Export::convert(unsigned eoffs, unsigned esize) { ordinals = New(char, len + 1); memcpy(ordinals, base + edir.ordinaltable, len); size += len; - iv.add(edir.ordinaltable, len); + iv.add_interval(edir.ordinaltable, len); iv.flatten(); if (iv.ivnum == 1) iv.clear(); @@ -1319,11 +1327,11 @@ struct PeFile::tls_traits final { byte _[8]; // zero init, characteristics }; - static const unsigned sotls = 24; - static const unsigned cb_size = 4; + static constexpr unsigned sotls = 24; + static constexpr unsigned cb_size = 4; typedef unsigned cb_value_t; - static const unsigned reloc_type = IMAGE_REL_BASED_HIGHLOW; - static const int tls_handler_offset_reloc = 4; + static constexpr unsigned reloc_type = IMAGE_REL_BASED_HIGHLOW; + static constexpr int tls_handler_offset_reloc = 4; }; template <> @@ -1336,11 +1344,11 @@ struct PeFile::tls_traits final { byte _[8]; // zero init, characteristics }; - static const unsigned sotls = 40; - static const unsigned cb_size = 8; + static constexpr unsigned sotls = 40; + static constexpr unsigned cb_size = 8; typedef upx_uint64_t cb_value_t; - static const unsigned reloc_type = IMAGE_REL_BASED_DIR64; - static const int tls_handler_offset_reloc = -1; // no need to relocate + static constexpr unsigned reloc_type = IMAGE_REL_BASED_DIR64; + static constexpr int tls_handler_offset_reloc = -1; // no need to relocate }; template @@ -1349,7 +1357,7 @@ void PeFile::processTls1(Interval *iv, typename tls_traits::cb_value_t ima { typedef typename tls_traits::tls tls; typedef typename tls_traits::cb_value_t cb_value_t; - const unsigned cb_size = tls_traits::cb_size; + constexpr unsigned cb_size = tls_traits::cb_size; COMPILE_TIME_ASSERT(sizeof(tls) == tls_traits::sotls) COMPILE_TIME_ASSERT_ALIGNED1(tls) @@ -1401,7 +1409,7 @@ void PeFile::processTls1(Interval *iv, typename tls_traits::cb_value_t ima unsigned pos, type; while (rel.next(pos, type)) if (pos >= tlsdatastart && pos < tlsdataend) - iv->add(pos, type); + iv->add_interval(pos, type); sotls = sizeof(tls) + tlsdataend - tlsdatastart; // if TLS callbacks are used, we need two more {D|Q}WORDS at the end of the TLS @@ -1436,21 +1444,22 @@ void PeFile::processTls2(Reloc *const rel, const Interval *const iv, unsigned ne { typedef typename tls_traits::tls tls; typedef typename tls_traits::cb_value_t cb_value_t; - const unsigned cb_size = tls_traits::cb_size; - const unsigned reloc_type = tls_traits::reloc_type; - const int tls_handler_offset_reloc = tls_traits::tls_handler_offset_reloc; + constexpr unsigned cb_size = tls_traits::cb_size; + constexpr unsigned reloc_type = tls_traits::reloc_type; + static_assert(reloc_type > IMAGE_REL_BASED_IGNORE && reloc_type < 16); + constexpr int tls_handler_offset_reloc = tls_traits::tls_handler_offset_reloc; if (sotls == 0) return; // add new relocation entries if (tls_handler_offset > 0 && tls_handler_offset_reloc > 0) - rel->add(tls_handler_offset + tls_handler_offset_reloc, reloc_type); + rel->add_reloc(tls_handler_offset + tls_handler_offset_reloc, reloc_type); unsigned ic; // NEW: if TLS callbacks are used, relocate the VA of the callback chain, too - Stefan Widmann for (ic = 0; ic < (use_tls_callbacks ? 4 * cb_size : 3 * cb_size); ic += cb_size) - rel->add(newaddr + ic, reloc_type); + rel->add_reloc(newaddr + ic, reloc_type); SPAN_S_VAR(tls, const tlsp, mb_otls); // now the relocation entries in the tls data area @@ -1462,9 +1471,9 @@ void PeFile::processTls2(Reloc *const rel, const Interval *const iv, unsigned ne if (kc < tlsp->dataend && kc >= tlsp->datastart) { kc += newaddr + sizeof(tls) - tlsp->datastart; *p = kc + imagebase; - rel->add(kc, iv->ivarr[ic].len); + rel->add_reloc(kc, iv->ivarr[ic].len); } else - rel->add(kc - imagebase, iv->ivarr[ic].len); + rel->add_reloc(kc - imagebase, iv->ivarr[ic].len); } const unsigned tls_data_size = tlsp->dataend - tlsp->datastart; @@ -1483,7 +1492,7 @@ void PeFile::processTls2(Reloc *const rel, const Interval *const iv, unsigned ne pp = otls + (sotls - 1 * cb_size); *(LEXX *) raw_bytes(pp, sizeof(LEXX)) = 0; // end of one-item list // add relocation for TLS handler offset - rel->add(newaddr + sotls - 2 * cb_size, reloc_type); + rel->add_reloc(newaddr + sotls - 2 * cb_size, reloc_type); } } @@ -1501,7 +1510,7 @@ void PeFile::processLoadConf(Interval *iv) // pass 1 soloadconf = get_le32(loadconf); if (soloadconf == 0) return; - static const unsigned MAX_SOLOADCONF = 256; // XXX FIXME: Why? + static constexpr unsigned MAX_SOLOADCONF = 256; // XXX FIXME: Why? if (soloadconf > MAX_SOLOADCONF) info("Load Configuration directory %u > %u", soloadconf, MAX_SOLOADCONF); @@ -1513,7 +1522,7 @@ void PeFile::processLoadConf(Interval *iv) // pass 1 unsigned pos, type; while (rel.next(pos, type)) if (pos >= lcaddr && pos < lcaddr + soloadconf) { - iv->add(pos - lcaddr, type); + iv->add_interval(pos - lcaddr, type); NO_printf("loadconf reloc detected: %x\n", pos); } @@ -1528,7 +1537,7 @@ void PeFile::processLoadConf(Reloc *rel, const Interval *iv, // now we have the address of the new load config table // so we can create the new relocation entries for (unsigned ic = 0; ic < iv->ivnum; ic++) { - rel->add(iv->ivarr[ic].start + newaddr, iv->ivarr[ic].len); + rel->add_reloc(iv->ivarr[ic].start + newaddr, iv->ivarr[ic].len); NO_printf("loadconf reloc added: %x %d\n", iv->ivarr[ic].start + newaddr, iv->ivarr[ic].len); } @@ -1812,14 +1821,14 @@ void PeFile::Resource::dump(const upx_rnode *node, unsigned level) const { void PeFile::Resource::clear(byte *node, unsigned level, Interval *iv) { if (level == 3) - iv->add(node, sizeof(res_data)); + iv->add_interval(node, sizeof(res_data)); else { const res_dir *const rd = (res_dir *) node; const unsigned n = rd->identr + rd->namedentr; const res_dir_entry *rde = rd->entries; for (unsigned ic = 0; ic < n; ic++, rde++) clear(newstart + (rde->child & 0x7fffffff), level + 1, iv); - iv->add(rd, rd->Sizeof()); + iv->add_interval(rd, rd->Sizeof()); } } @@ -2194,7 +2203,7 @@ unsigned PeFile::readSections(unsigned objs, unsigned usize, unsigned ih_fileali isection[ic].vsize = isection[ic].size; if ((isection[ic].flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA) || isection[ic].rawdataptr == 0 || (isection[ic].flags & IMAGE_SCN_LNK_INFO)) { - // holes.add(isection[ic].vaddr,isection[ic].vsize); + // holes.add_interval(isection[ic].vaddr, isection[ic].vsize); continue; } if (isection[ic].vaddr + isection[ic].size > usize) @@ -2722,10 +2731,10 @@ void PeFile::rebuildRelocs(SPAN_S(byte) & extra_info, unsigned bits, unsigned fl if (big & 6) { // add 16-bit relocations SPAN_S_VAR(const LE32, q, SPAN_TYPE_CAST(const LE32, rdata)); while (*q) - rel.add(*q++ + rvamin, (big & 4) ? 2 : 1); + rel.add_reloc(*q++ + rvamin, (big & 4) ? IMAGE_REL_BASED_LOW : IMAGE_REL_BASED_HIGH); if ((big & 6) == 6) while (*++q) - rel.add(*q + rvamin, 1); + rel.add_reloc(*q + rvamin, IMAGE_REL_BASED_HIGH); // rdata = (const byte *) raw_bytes(q, 0); // advance rdata } @@ -2736,8 +2745,8 @@ void PeFile::rebuildRelocs(SPAN_S(byte) & extra_info, unsigned bits, unsigned fl set_le32(p, get_le32(p) + imagebase + rvamin); else set_le64(p, get_le64(p) + imagebase + rvamin); - rel.add(rvamin + get_le32(wrkmem + 4 * ic), - bits == 32 ? IMAGE_REL_BASED_HIGHLOW : IMAGE_REL_BASED_DIR64); + rel.add_reloc(rvamin + get_le32(wrkmem + 4 * ic), + bits == 32 ? IMAGE_REL_BASED_HIGHLOW : IMAGE_REL_BASED_DIR64); } rel.finish(oxrelocs, soxrelocs); diff --git a/src/pefile.h b/src/pefile.h index f761bea8..7bb188cf 100644 --- a/src/pefile.h +++ b/src/pefile.h @@ -356,9 +356,9 @@ protected: RT_LAST }; - enum { + enum { // 4-bit reloc_type in IMAGE_BASE_RELOCATION relocations IMAGE_REL_BASED_ABSOLUTE = 0, // this relocation is ignored - IMAGE_REL_BASED_IGNORE = 0, // (unofficial name) + IMAGE_REL_BASED_IGNORE = 0, // (unofficial UPX name) IMAGE_REL_BASED_HIGH = 1, IMAGE_REL_BASED_LOW = 2, IMAGE_REL_BASED_HIGHLOW = 3, @@ -372,8 +372,8 @@ protected: }; class Interval final : private noncopyable { - unsigned capacity = 0; - void *base = nullptr; + SPAN_0(byte) base = nullptr; + unsigned ivcapacity = 0; // for ivarr public: struct interval { unsigned start, len; @@ -381,13 +381,13 @@ protected: struct interval *ivarr = nullptr; unsigned ivnum = 0; - explicit Interval(void *b); + explicit Interval(SPAN_P(byte)); ~Interval() noexcept; - void add(unsigned start, unsigned len); - void add(const void *start, unsigned len); - void add(const void *start, const void *end); - void add(const Interval *iv); + void add_interval(unsigned start, unsigned len); + void add_interval(const void *start, unsigned len); + void add_interval(const void *start, const void *end); + void add_interval(const Interval *other); void flatten(); void clear(); @@ -407,7 +407,7 @@ protected: struct alignas(1) BaseReloc { // IMAGE_BASE_RELOCATION LE32 virtual_address; LE32 size_of_block; - // LE16 rel1[COUNT]; // COUNT == (size_of_block - 8) / 2 + // LE16 rel1[COUNT]; // actual relocations; COUNT == (size_of_block - 8) / 2 }; struct RelocationBlock { SPAN_0(BaseReloc) rel = nullptr; @@ -429,7 +429,7 @@ protected: bool next(unsigned &result_pos, unsigned &result_type); const unsigned *getcounts() const { return counts; } // - void add(unsigned pos, unsigned type); + void add_reloc(unsigned pos, unsigned type); void finish(byte *(&result_ptr), unsigned &result_size); // => transfer ownership }; diff --git a/src/util/cxxlib.h b/src/util/cxxlib.h index 6b2f8ca8..6cd85f01 100644 --- a/src/util/cxxlib.h +++ b/src/util/cxxlib.h @@ -133,6 +133,13 @@ private: UPX_CXX_DISABLE_NEW_DELETE_IMPL_CSUDF_B__(Klass) \ UPX_CXX_DISABLE_NEW_DELETE_IMPL_CSUDDF_B__(Klass) +#if defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION) // do not use std::align_val_t +#undef UPX_CXX_DISABLE_NEW_DELETE +#undef UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL +#define UPX_CXX_DISABLE_NEW_DELETE(Klass) private: +#define UPX_CXX_DISABLE_NEW_DELETE_NO_VIRTUAL(Klass) private: +#endif + /************************************************************************* // type_traits **************************************************************************/ diff --git a/src/util/system_features.h b/src/util/system_features.h new file mode 100644 index 00000000..1b2bc864 --- /dev/null +++ b/src/util/system_features.h @@ -0,0 +1,61 @@ +/* system_features.h -- libc and libc++ features + + This file is part of the UPX executable compressor. + + Copyright (C) 1996-2024 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + UPX and the UCL library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + Markus F.X.J. Oberhumer + + */ + +#pragma once + +#include "system_defs.h" + +#if defined(__has_include) +#if __has_include() +#include // for __GLIBC__ +#endif +#endif + +// aligned_alloc() was added in glibc-2.16 +#if !defined(_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION) && defined(__cplusplus) +#if defined(__GLIBC__) && defined(__GLIBC_MINOR__) && (__GLIBC__ + 0 == 2) && \ + (__GLIBC_MINOR__ + 0 > 0) && (__GLIBC_MINOR__ + 0 < 16) +#define _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION +#endif +#endif // _LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION + +#if 0 // TODO later +// libc++ hardenining +#if defined(__clang__) && defined(__clang_major__) && (__clang_major__ + 0 >= 18) +#if DEBUG +#define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_DEBUG +#else +#define _LIBCPP_HARDENING_MODE _LIBCPP_HARDENING_MODE_EXTENSIVE +#endif +#endif +#if defined(__clang__) && defined(__clang_major__) && (__clang_major__ + 0 < 18) +#if DEBUG +#define _LIBCPP_ENABLE_ASSERTIONS 1 +#endif +#endif +#endif // TODO later + +/* vim:set ts=4 sw=4 et: */ diff --git a/src/util/system_headers.h b/src/util/system_headers.h index c3d0c2cf..3af25132 100644 --- a/src/util/system_headers.h +++ b/src/util/system_headers.h @@ -90,6 +90,7 @@ static_assert(sizeof(void *) == sizeof(long)); #endif // ACC and C system headers +#include "system_features.h" #ifndef ACC_CFG_USE_NEW_STYLE_CASTS #define ACC_CFG_USE_NEW_STYLE_CASTS 1 #endif