From b8d9c2b75540a0964ef14886ebe8ba8054d1dba7 Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Sun, 5 Feb 2023 17:20:32 +0100 Subject: [PATCH] all: assorted updates and cleanups --- .clang-format | 2 + .github/workflows/ci.yml | 26 +- .github/workflows/close-stale-issues.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/minimal-ci.yml | 2 +- .github/workflows/scan-build.yml | 2 +- CMakeLists.txt | 108 ++--- Makefile | 8 +- NEWS => NEWS.md | 9 +- doc/upx.1 | 2 +- .../10-create-image.sh | 4 +- .../20-image-run-shell.sh | 9 +- misc/cross-compile-upx-with-podman/Dockerfile | 6 +- .../build-all-inside-container.sh | 10 +- .../10-create-image.sh | 2 +- .../20-image-run-shell.sh | 2 +- misc/rebuild-stubs-with-podman/Dockerfile | 13 +- src/Makefile | 4 +- src/conf.h | 24 +- src/except.cpp | 14 +- src/except.h | 6 +- src/filter.cpp | 20 +- src/filter.h | 6 +- src/filter/filter_impl.cpp | 4 +- src/p_armpe.cpp | 34 +- src/p_com.cpp | 113 +++--- src/p_com.h | 9 +- src/p_djgpp2.cpp | 31 +- src/p_djgpp2.h | 4 +- src/p_exe.cpp | 46 +-- src/p_exe.h | 2 +- src/p_lx_elf.cpp | 1 + src/p_lx_sh.cpp | 2 +- src/p_mach.cpp | 1 + src/p_sys.cpp | 52 ++- src/p_sys.h | 6 +- src/p_tmt.cpp | 18 +- src/p_tos.cpp | 4 +- src/p_vmlinz.cpp | 1 + src/p_w32pe.cpp | 26 +- src/p_w64pep.cpp | 26 +- src/p_wcle.cpp | 10 +- src/packer.cpp | 26 +- src/packer.h | 1 - src/packer_c.cpp | 5 +- src/packer_f.cpp | 380 ++++++++---------- src/pefile.cpp | 86 ++-- src/ui.cpp | 17 +- src/util/bptr.h | 155 ------- src/util/membuffer.cpp | 132 +++--- src/util/membuffer.h | 47 ++- src/util/util.cpp | 4 +- src/util/xspan.h | 3 +- src/util/xspan_fwd.h | 4 + src/version.h | 4 +- src/work.cpp | 7 +- 56 files changed, 691 insertions(+), 853 deletions(-) rename NEWS => NEWS.md (99%) delete mode 100644 src/util/bptr.h diff --git a/.clang-format b/.clang-format index 137b7a62..9d4d8c2d 100644 --- a/.clang-format +++ b/.clang-format @@ -18,6 +18,8 @@ AttributeMacros: - __acc_noinline - __acc_static_noinline - __acc_static_forceinline + - DELETED_FUNCTION + - XSPAN_DELETED_FUNCTION - forceinline - noinline EmptyLineBeforeAccessModifier: Leave diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a9096df7..5fecd5ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -101,6 +101,10 @@ jobs: with: name: ${{ env.artifact_name }} path: tmp/artifact + - name: 'Run install tests' + run: | + (cd build/extra/gcc/release && DESTDIR=$PWD/Install-with-cmake cmake --install .) + (cd build/extra/gcc/release && DESTDIR=$PWD/Install-with-make make install) - name: 'Run basic tests' run: | make -C build/extra/gcc/debug test @@ -171,6 +175,10 @@ jobs: with: name: ${{ env.artifact_name }} path: tmp/artifact + - name: 'Run install tests' + run: | + (cd build/extra/clang/release && DESTDIR=$PWD/Install-with-cmake cmake --install .) + (cd build/extra/clang/release && DESTDIR=$PWD/Install-with-make make install) - name: 'Run basic tests' run: | make -C build/extra/clang/debug test @@ -250,12 +258,12 @@ jobs: fail-fast: false matrix: include: - - { name: amd64-win64-vs2019, os: windows-2019, C: msvc-14.2-x64, arch: amd64 } - - { name: amd64-win64-vs2022, os: windows-2022, C: msvc-14.3-x64, arch: amd64 } - - { name: arm64-win64-vs2019, os: windows-2019, C: msvc-14.2-x64, arch: amd64_arm64 } - - { name: arm64-win64-vs2022, os: windows-2022, C: msvc-14.3-x64, arch: amd64_arm64 } - - { name: i386-win32-vs2019, os: windows-2019, C: msvc-14.2-x86, arch: amd64_x86 } - - { name: i386-win32-vs2022, os: windows-2022, C: msvc-14.3-x86, arch: amd64_x86 } + - { name: amd64-win64-vs2019, os: windows-2019, C: msvc-14.2-x64, arch: amd64 } + - { name: amd64-win64-vs2022, os: windows-2022, C: msvc-14.3-x64, arch: amd64 } + - { name: arm64-win64-vs2019, os: windows-2019, C: msvc-14.2-arm64, arch: amd64_arm64 } + - { name: arm64-win64-vs2022, os: windows-2022, C: msvc-14.3-arm64, arch: amd64_arm64 } + - { name: i386-win32-vs2019, os: windows-2019, C: msvc-14.2-x86, arch: amd64_x86 } + - { name: i386-win32-vs2022, os: windows-2022, C: msvc-14.3-x86, arch: amd64_x86 } steps: - name: 'Check out code' uses: actions/checkout@v3 @@ -358,8 +366,8 @@ jobs: - { zig_target: x86_64-macos.13-none } - { zig_target: x86_64-windows-gnu } env: - # 2023-01-30 - ZIG_DIST_VERSION: 0.11.0-dev.1491+2b27bc2c6 + # 2023-02-05 + ZIG_DIST_VERSION: 0.11.0-dev.1575+289e8fab7 # for zig-cc wrapper scripts (see below): ZIG_CPPFLAGS: -DUPX_DOCTEST_CONFIG_MULTITHREADING ZIG_FLAGS: ${{ matrix.zig_flags }} @@ -391,7 +399,7 @@ jobs: mkdir -p -v ~/.local/bin cd ~/.local/bin ZIG_DIST_NAME=zig-linux-x86_64-${ZIG_DIST_VERSION} - wget -q 'https://ziglang.org/builds/'${ZIG_DIST_NAME}.tar.xz + wget -q https://ziglang.org/builds/${ZIG_DIST_NAME}.tar.xz ls -l ${ZIG_DIST_NAME}.tar.xz tar -xoJf ${ZIG_DIST_NAME}.tar.xz rm ${ZIG_DIST_NAME}.tar.xz diff --git a/.github/workflows/close-stale-issues.yml b/.github/workflows/close-stale-issues.yml index 827dcbe9..639bacf2 100644 --- a/.github/workflows/close-stale-issues.yml +++ b/.github/workflows/close-stale-issues.yml @@ -13,7 +13,7 @@ name: 'GitHub - Close inactive issues' on: schedule: - - cron: '30 6 * * 4' + - cron: '10 4 * * 3' workflow_dispatch: jobs: close-issues: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 580ed0c1..60c2873d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -7,7 +7,7 @@ on: # # The branches below must be a subset of the branches above # branches: [ 'devel', 'devel4', 'devel5' ] schedule: - - cron: '20 1 * * 3' + - cron: '20 4 * * 3' workflow_dispatch: jobs: diff --git a/.github/workflows/minimal-ci.yml b/.github/workflows/minimal-ci.yml index 9ff854ad..41420801 100644 --- a/.github/workflows/minimal-ci.yml +++ b/.github/workflows/minimal-ci.yml @@ -2,7 +2,7 @@ name: 'CI - Minimal CI with Alpine Linux' -on: { workflow_dispatch: } +on: [workflow_dispatch] jobs: job-alpine-cmake: strategy: {matrix: {container: ['alpine:3.12','alpine:3.17','alpine:edge']}} diff --git a/.github/workflows/scan-build.yml b/.github/workflows/scan-build.yml index fa93370c..b320abbc 100644 --- a/.github/workflows/scan-build.yml +++ b/.github/workflows/scan-build.yml @@ -2,7 +2,7 @@ name: 'Static Analyzer - scan-build' on: schedule: - - cron: '40 1 * * 3' + - cron: '40 4 * * 3' workflow_dispatch: jobs: diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f6930d1..fad626a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,12 +5,14 @@ if(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git") # permissive config defaults when building from source code tarball option(UPX_CONFIG_DISABLE_GITREV "Do not compile with default Git version info." ON) option(UPX_CONFIG_DISABLE_SANITIZE "Do not compile with default sanitize options." ON) + option(UPX_CONFIG_DISABLE_WSTRICT "Do not compile with strict compiler warnings." ON) option(UPX_CONFIG_DISABLE_WERROR "Do not compile with default -Werror option." ON) else() - # strict config defaults for devel builds + # strict config defaults for Git developer builds message(STATUS "===== UPX info: strict config defaults enabled") option(UPX_CONFIG_DISABLE_GITREV "Do not compile with default Git version info." OFF) option(UPX_CONFIG_DISABLE_SANITIZE "Do not compile with default sanitize options." OFF) + option(UPX_CONFIG_DISABLE_WSTRICT "Do not compile with strict compiler warnings." OFF) option(UPX_CONFIG_DISABLE_WERROR "Do not compile with default -Werror option." OFF) endif() @@ -24,7 +26,7 @@ option(UPX_CONFIG_DISABLE_SELF_PACK_TEST "Do not test packing UPX with itself" O # Disallow in-source builds. Note that you will still have to manually # clean up a few files if you accidentally try an in-source build. -if(NOT MSVC_IDE) +if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git" AND NOT MSVC_IDE) set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) set(CMAKE_DISABLE_SOURCE_CHANGES ON) if(",${CMAKE_CURRENT_SOURCE_DIR}," STREQUAL ",${CMAKE_CURRENT_BINARY_DIR},") @@ -35,37 +37,36 @@ set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -# determine git revision +# determine Git revision set(GITREV_SHORT "") set(GITREV_PLUS "") set(GIT_DESCRIBE "") -find_package(Git) -if(Git_FOUND AND NOT UPX_CONFIG_DISABLE_GITREV) - execute_process( - COMMAND "${GIT_EXECUTABLE}" rev-parse --short=12 HEAD - RESULT_VARIABLE result ERROR_QUIET - OUTPUT_VARIABLE GITREV_SHORT OUTPUT_STRIP_TRAILING_WHITESPACE - ) - string(LENGTH "${GITREV_SHORT}" l) - if(${result} EQUAL 0 AND ${l} EQUAL 12) - execute_process(RESULT_VARIABLE result COMMAND "${GIT_EXECUTABLE}" diff --quiet) - if(NOT ${result} EQUAL 0) - set(GITREV_PLUS "+") +if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git" AND NOT UPX_CONFIG_DISABLE_GITREV) + find_package(Git) + if(Git_FOUND) + execute_process( + COMMAND "${GIT_EXECUTABLE}" rev-parse --short=12 HEAD + RESULT_VARIABLE result ERROR_QUIET + OUTPUT_VARIABLE GITREV_SHORT OUTPUT_STRIP_TRAILING_WHITESPACE + ) + string(LENGTH "${GITREV_SHORT}" l) + if(${result} EQUAL 0 AND ${l} EQUAL 12) + execute_process(RESULT_VARIABLE result COMMAND "${GIT_EXECUTABLE}" diff --quiet) + if(NOT ${result} EQUAL 0) + set(GITREV_PLUS "+") + endif() + else() + set(GITREV_SHORT "") + endif() + execute_process( + COMMAND "${GIT_EXECUTABLE}" describe --match "v*.*.*" --tags --dirty + RESULT_VARIABLE result ERROR_QUIET + OUTPUT_VARIABLE GIT_DESCRIBE OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(GIT_DESCRIBE MATCHES "^v?([0-9]+\\.[0-9]+\\.[0-9]+)-([0-9]+)-g(.+)$") + set(GIT_DESCRIBE "${CMAKE_MATCH_1}-devel.${CMAKE_MATCH_2}+git-${CMAKE_MATCH_3}") endif() - else() - set(GITREV_SHORT "") endif() - execute_process( - COMMAND "${GIT_EXECUTABLE}" describe --match "v*.*.*" --tags --dirty - RESULT_VARIABLE result ERROR_QUIET - OUTPUT_VARIABLE GIT_DESCRIBE OUTPUT_STRIP_TRAILING_WHITESPACE - ) - if(GIT_DESCRIBE MATCHES "^v?([0-9]+\\.[0-9]+\\.[0-9]+)-([0-9]+)-g(.+)$") - set(GIT_DESCRIBE "${CMAKE_MATCH_1}-devel.${CMAKE_MATCH_2}+git-${CMAKE_MATCH_3}") - endif() -endif() -if(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git") # extra check - set(GITREV_SHORT "") endif() if(GITREV_SHORT) message(STATUS "UPX_VERSION_GITREV = \"${GITREV_SHORT}${GITREV_PLUS}\"") @@ -87,7 +88,7 @@ if(is_multi_config) set(c "${CMAKE_CONFIGURATION_TYPES}") list(INSERT c 0 "Release") list(INSERT c 1 "Debug") - if (CMAKE_BUILD_TYPE) + if(CMAKE_BUILD_TYPE) list(INSERT c 0 "${CMAKE_BUILD_TYPE}") endif() list(REMOVE_DUPLICATES c) @@ -97,7 +98,7 @@ elseif(NOT CMAKE_BUILD_TYPE) endif() #*********************************************************************** -# targets and compilation flags +# targets #*********************************************************************** #find_package(Threads) # multithreading is currently not used; maybe in UPX version 5 @@ -126,12 +127,18 @@ add_executable(upx ${upx_SOURCES}) set_property(TARGET upx PROPERTY CXX_STANDARD 17) target_link_libraries(upx upx_vendor_ucl upx_vendor_zlib) -if(NOT MSVC) - # rather strict default compilation warnings - set(warn_strict - -Wall -Wextra -Wcast-align -Wcast-qual -Wmissing-declarations - -Wpointer-arith -Wshadow -Wvla -Wwrite-strings - ) +#*********************************************************************** +# compilation flags +#*********************************************************************** + +if(UPX_CONFIG_DISABLE_WSTRICT) + # enable all basic warnings + set(warn_Wall -Wall) + set(warn_WN -W3) +else() + # enable lots of strict warnings + set(warn_Wall -Wall -Wextra -Wcast-align -Wcast-qual -Wmissing-declarations -Wpointer-arith -Wshadow -Wvla -Wwrite-strings) + set(warn_WN -W4) endif() if(UPX_CONFIG_DISABLE_WERROR) set(warn_Werror "") @@ -159,7 +166,7 @@ if(MSVC) add_definitions(-Zc:__cplusplus -Zc:preprocessor) else() # protect against security threats caused by misguided compiler "optimizations" - if (CMAKE_C_COMPILER_ID STREQUAL "GNU") + if(CMAKE_C_COMPILER_ID STREQUAL "GNU") add_definitions(-fno-delete-null-pointer-checks -fno-lifetime-dse) endif() add_definitions(-fno-strict-aliasing -fno-strict-overflow -funsigned-char) @@ -167,7 +174,7 @@ else() add_definitions(-fno-tree-vectorize) endif() -# compile a target with -O2 in Debug build +# compile a target with -O2 even in Debug build function(upx_compile_target_debug_with_O2 t) if(MSVC) # msvc uses some Debug compile options like -RTC1 that are incompatible with -O2 @@ -195,9 +202,9 @@ target_include_directories(${t} PRIVATE vendor/ucl/include vendor/ucl) upx_compile_target_debug_with_O2(${t}) upx_sanitize_target(${t}) if(MSVC) - target_compile_options(${t} PRIVATE -J -W4 ${warn_WX}) + target_compile_options(${t} PRIVATE -J ${warn_WN} ${warn_WX}) else() - target_compile_options(${t} PRIVATE ${warn_strict} ${warn_Werror}) + target_compile_options(${t} PRIVATE ${warn_Wall} ${warn_Werror}) endif() set(t upx_vendor_zlib) @@ -208,7 +215,8 @@ if(MSVC) else() target_compile_options(${t} PRIVATE -DHAVE_STDARG_H -DHAVE_UNISTD_H -DHAVE_VSNPRINTF) # clang-15: -Wno-strict-prototypes is needed to silence the new -Wdeprecated-non-prototype warning - target_compile_options(${t} PRIVATE -Wall -Wextra -Wvla -Wno-strict-prototypes ${warn_Werror}) + target_compile_options(${t} PRIVATE -Wall -Wno-strict-prototypes ${warn_Werror}) + ##target_compile_options(${t} PRIVATE ${warn_Wall} -Wno-cast-align -Wno-cast-qual -Wno-strict-prototypes ${warn_Werror}) endif() if(NOT UPX_CONFIG_DISABLE_ZSTD) @@ -217,9 +225,9 @@ upx_compile_target_debug_with_O2(${t}) upx_sanitize_target(${t}) target_compile_options(${t} PRIVATE -DDYNAMIC_BMI2=0 -DZSTD_DISABLE_ASM) if(MSVC) - target_compile_options(${t} PRIVATE -J -W4 ${warn_WX}) + target_compile_options(${t} PRIVATE -J ${warn_WN} ${warn_WX}) else() - target_compile_options(${t} PRIVATE ${warn_strict} ${warn_Werror}) + target_compile_options(${t} PRIVATE ${warn_Wall} ${warn_Werror}) endif() endif() @@ -232,12 +240,18 @@ if(GITREV_SHORT) target_compile_definitions(${t} PRIVATE UPX_VERSION_GIT_DESCRIBE="${GIT_DESCRIBE}") endif() endif() +if(UPX_CONFIG_DISABLE_WSTRICT) + target_compile_definitions(${t} PRIVATE UPX_CONFIG_DISABLE_WSTRICT=1) +endif() +if(UPX_CONFIG_DISABLE_WERROR) + target_compile_definitions(${t} PRIVATE UPX_CONFIG_DISABLE_WERROR=1) +endif() #upx_compile_target_debug_with_O2(${t}) upx_sanitize_target(${t}) if(MSVC) - target_compile_options(${t} PRIVATE -EHsc -J -W4 ${warn_WX}) + target_compile_options(${t} PRIVATE -EHsc -J ${warn_WN} ${warn_WX}) else() - target_compile_options(${t} PRIVATE ${warn_strict} ${warn_Werror}) + target_compile_options(${t} PRIVATE ${warn_Wall} ${warn_Werror}) endif() if(NOT UPX_CONFIG_DISABLE_ZSTD) target_compile_definitions(${t} PRIVATE WITH_ZSTD=1) @@ -302,7 +316,7 @@ endif() if(CMAKE_INSTALL_PREFIX AND DEFINED CMAKE_INSTALL_FULL_BINDIR) install(TARGETS upx DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}") install(FILES - COPYING LICENSE NEWS README THANKS doc/upx-doc.html doc/upx-doc.txt + COPYING LICENSE NEWS.md README THANKS doc/upx-doc.html doc/upx-doc.txt DESTINATION "${CMAKE_INSTALL_FULL_DOCDIR}" ) install(FILES doc/upx.1 DESTINATION "${CMAKE_INSTALL_FULL_MANDIR}/man1") @@ -332,7 +346,7 @@ print_var(CMAKE_C_COMPILER_ID CMAKE_C_COMPILER_VERSION CMAKE_C_COMPILER_ARCHITEC print_var(CMAKE_CXX_COMPILER_ID CMAKE_CXX_COMPILER_VERSION CMAKE_CXX_COMPILER_ARCHITECTURE_ID CMAKE_CXX_PLATFORM_ID CMAKE_CXX_COMPILER_ABI) endif() # UPX_CONFIG_CMAKE_DISABLE_PRINT_INFO print_var(CMAKE_INSTALL_PREFIX CMAKE_CONFIGURATION_TYPES CMAKE_BUILD_TYPE) -if (CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE MATCHES "^(Debug|Release)$") +if(CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE MATCHES "^(Debug|Release)$") message(WARNING "WARNING: unsupported CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}; please use \"Debug\" or \"Release\"") endif() diff --git a/Makefile b/Makefile index 974ae247..4b36a523 100644 --- a/Makefile +++ b/Makefile @@ -128,14 +128,14 @@ build/extra/cross-linux-arm/%: export CXX = arm-linux-gnueabihf-g++ -Wno-psabi # cross compiler: Windows x86 win32 MinGW build/extra/cross-windows-mingw32/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/cross-windows-mingw32/release: PHONY; $(call run_config_and_build,$@,Release) -build/extra/cross-windows-mingw32/%: export CC = i686-w64-mingw32-gcc -build/extra/cross-windows-mingw32/%: export CXX = i686-w64-mingw32-g++ +build/extra/cross-windows-mingw32/%: export CC = i686-w64-mingw32-gcc -static +build/extra/cross-windows-mingw32/%: export CXX = i686-w64-mingw32-g++ -static # cross compiler: Windows x64 win64 MinGW build/extra/cross-windows-mingw64/debug: PHONY; $(call run_config_and_build,$@,Debug) build/extra/cross-windows-mingw64/release: PHONY; $(call run_config_and_build,$@,Release) -build/extra/cross-windows-mingw64/%: export CC = x86_64-w64-mingw32-gcc -build/extra/cross-windows-mingw64/%: export CXX = x86_64-w64-mingw32-g++ +build/extra/cross-windows-mingw64/%: export CC = x86_64-w64-mingw32-gcc -static +build/extra/cross-windows-mingw64/%: export CXX = x86_64-w64-mingw32-g++ -static # cross compiler: macOS arm64 build/extra/cross-darwin-arm64/debug: PHONY; $(call run_config_and_build,$@,Debug) diff --git a/NEWS b/NEWS.md similarity index 99% rename from NEWS rename to NEWS.md index 1839b4e9..42ce722e 100644 --- a/NEWS +++ b/NEWS.md @@ -1,5 +1,5 @@ ================================================================== -User visible changes for UPX +### User visible changes for UPX ================================================================== Changes in 4.0.3 (XX XXX 2023): @@ -78,7 +78,7 @@ Changes in 3.08 (12 Dec 2011): * Compress shared library on ELF i386 only [ld.so threatens even this case]. * Attempt to support ELF on QNX 6.3.0 for armel (experimental). * Better diagnostic when ELF -fPIC is needed. - * PT_NOTE improvements for *BSD. + * PT_NOTE improvements for BSD. * Preserve more ELF .e_flags on ARM. * Minor code improvements for ELF stubs. * Defend against another flavor of corrupt PE header. @@ -258,7 +258,7 @@ Changes in 1.11 beta (20 Dec 2000): ================================================================== Changes in 1.25 (29 Jun 2004) - * INFO: http://upx.sourceforge.net is the permanent UPX home page + * INFO: http://upx.sourceforge.net is the new UPX home page * watcom/le: don't crash on files without relocations * win32/pe: stricter checks of some PE values * source code: much improved portability using ACC, the @@ -539,6 +539,3 @@ Changes in 0.20 (05 Jul 1998) Changes in 0.05 (26 May 1998) * first public beta release - - -# vim:set syntax=off tw=0 ts=4 sw=4 et: -*- coding: utf-8 -*- diff --git a/doc/upx.1 b/doc/upx.1 index f1d85eea..a3a5daed 100644 --- a/doc/upx.1 +++ b/doc/upx.1 @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "UPX 1" -.TH UPX 1 "2023-01-30" "upx 4.0.3" " " +.TH UPX 1 "2023-02-05" "upx 4.0.3" " " .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff --git a/misc/cross-compile-upx-with-podman/10-create-image.sh b/misc/cross-compile-upx-with-podman/10-create-image.sh index 80e8fbcc..901ba732 100755 --- a/misc/cross-compile-upx-with-podman/10-create-image.sh +++ b/misc/cross-compile-upx-with-podman/10-create-image.sh @@ -6,10 +6,10 @@ argv0=$0; argv0abs="$(readlink -fn "$argv0")"; argv0dir="$(dirname "$argv0abs")" # create the image from Dockerfile # using a rootless Podman container -# NOTE: this image is based on rebuild-stubs-with-podman/upx-stubtools-20221212-v4, +# NOTE: this image is based on rebuild-stubs-with-podman/upx-stubtools-20221212-v5, # so you have to create that image first # WARNING: we install many packages, so the resulting image needs A LOT of disk space! -image=upx-cross-compile-20230115-v2 +image=upx-cross-compile-20230115-v3 podman build -t "$image" -f "$argv0dir/Dockerfile" "$argv0dir" diff --git a/misc/cross-compile-upx-with-podman/20-image-run-shell.sh b/misc/cross-compile-upx-with-podman/20-image-run-shell.sh index 984e9766..8ae8c984 100755 --- a/misc/cross-compile-upx-with-podman/20-image-run-shell.sh +++ b/misc/cross-compile-upx-with-podman/20-image-run-shell.sh @@ -6,7 +6,7 @@ argv0=$0; argv0abs="$(readlink -fn "$argv0")"; argv0dir="$(dirname "$argv0abs")" # run an interactive shell in the image # using a rootless Podman container -image=upx-cross-compile-20230115-v2 +image=upx-cross-compile-20230115-v3 flags=( -ti --read-only --rm ) flags+=( --cap-drop=all ) # drop all capabilities @@ -44,10 +44,11 @@ podman run "${flags[@]}" "$image" bash -l # and lots of other cross-compilers are installed; see "ls /usr/bin/*g++*" -# and finally see misc/cross-compile-upx-with-podman/build-all-inside-container.sh +# and finally see +# ./misc/cross-compile-upx-with-podman/build-all-inside-container.sh # after running that script we can do cool things like: # cd /home/upx/src/upx/build/cross-compile-upx-with-podman/alpha-linux-gnu/debug -# qemu-alpha -L /usr/alpha-linux-gnu upx --version +# qemu-alpha -L /usr/alpha-linux-gnu ./upx --version # cd /home/upx/src/upx/build/cross-compile-upx-with-podman/hppa-linux-gnu/debug -# qemu-hppa -L /usr/hppa-linux-gnu upx --version +# qemu-hppa -L /usr/hppa-linux-gnu ./upx --version # (similar for many other architectures/builds) diff --git a/misc/cross-compile-upx-with-podman/Dockerfile b/misc/cross-compile-upx-with-podman/Dockerfile index 0dd5f9dd..c55e2c44 100644 --- a/misc/cross-compile-upx-with-podman/Dockerfile +++ b/misc/cross-compile-upx-with-podman/Dockerfile @@ -1,8 +1,8 @@ -# NOTE: this image is based on rebuild-stubs-with-podman/upx-stubtools-20221212-v4, +# NOTE: this image is based on rebuild-stubs-with-podman/upx-stubtools-20221212-v5, # so you have to create that image first # WARNING: we install many packages, so the resulting image needs A LOT of disk space! -FROM localhost/upx-stubtools-20221212-v4 -ENV UPX_CONTAINER_IMAGE_NAME=upx-cross-compile-20230115-v2 +FROM localhost/upx-stubtools-20221212-v5 +ENV UPX_CONTAINER_IMAGE_NAME=upx-cross-compile-20230115-v3 ARG DEBIAN_FRONTEND=noninteractive USER root diff --git a/misc/cross-compile-upx-with-podman/build-all-inside-container.sh b/misc/cross-compile-upx-with-podman/build-all-inside-container.sh index c1a1c938..fea2226a 100755 --- a/misc/cross-compile-upx-with-podman/build-all-inside-container.sh +++ b/misc/cross-compile-upx-with-podman/build-all-inside-container.sh @@ -27,9 +27,13 @@ function run_config_and_build { # these old architectures do not support sanitize alpha-linux-gnu) cmake_config_flags=-DUPX_CONFIG_DISABLE_SANITIZE=ON ;; hppa-linux-gnu) cmake_config_flags=-DUPX_CONFIG_DISABLE_SANITIZE=ON ;; - # avoid link errors with current MinGW-w64 versions - i686-w64-mingw32) cmake_config_flags=-DUPX_CONFIG_DISABLE_SANITIZE=ON ;; - x86_64-w64-mingw32) cmake_config_flags=-DUPX_CONFIG_DISABLE_SANITIZE=ON ;; + # avoid sanitize link errors with current MinGW-w64 versions; link libstdc++ statically + i686-w64-mingw32) + cmake_config_flags=-DUPX_CONFIG_DISABLE_SANITIZE=ON + CC="$CC -static"; CXX="$CXX -static" ;; + x86_64-w64-mingw32) + cmake_config_flags=-DUPX_CONFIG_DISABLE_SANITIZE=ON + CC="$CC -static"; CXX="$CXX -static" ;; # avoid warnings about arm libstdc++ ABI change in gcc-7 arm-linux-*) CXX="$CXX -Wno-psabi" ;; esac diff --git a/misc/rebuild-stubs-with-podman/10-create-image.sh b/misc/rebuild-stubs-with-podman/10-create-image.sh index abe8e753..b6232fee 100755 --- a/misc/rebuild-stubs-with-podman/10-create-image.sh +++ b/misc/rebuild-stubs-with-podman/10-create-image.sh @@ -6,7 +6,7 @@ argv0=$0; argv0abs="$(readlink -fn "$argv0")"; argv0dir="$(dirname "$argv0abs")" # create the image from Dockerfile # using a rootless Podman container -image=upx-stubtools-20221212-v4 +image=upx-stubtools-20221212-v5 podman build -t "$image" -f "$argv0dir/Dockerfile" "$argv0dir" diff --git a/misc/rebuild-stubs-with-podman/20-image-run-shell.sh b/misc/rebuild-stubs-with-podman/20-image-run-shell.sh index 38dd8b88..b32fc02d 100755 --- a/misc/rebuild-stubs-with-podman/20-image-run-shell.sh +++ b/misc/rebuild-stubs-with-podman/20-image-run-shell.sh @@ -6,7 +6,7 @@ argv0=$0; argv0abs="$(readlink -fn "$argv0")"; argv0dir="$(dirname "$argv0abs")" # run an interactive shell in the image # using a rootless Podman container -image=upx-stubtools-20221212-v4 +image=upx-stubtools-20221212-v5 flags=( -ti --read-only --rm ) flags+=( --cap-drop=all ) # drop all capabilities diff --git a/misc/rebuild-stubs-with-podman/Dockerfile b/misc/rebuild-stubs-with-podman/Dockerfile index d1e2df98..15d4b5e9 100644 --- a/misc/rebuild-stubs-with-podman/Dockerfile +++ b/misc/rebuild-stubs-with-podman/Dockerfile @@ -1,5 +1,5 @@ FROM docker.io/library/ubuntu:22.04 -ENV UPX_CONTAINER_IMAGE_NAME=upx-stubtools-20221212-v4 +ENV UPX_CONTAINER_IMAGE_NAME=upx-stubtools-20221212-v5 ARG DEBIAN_FRONTEND=noninteractive ENV LANG=C.UTF-8 @@ -7,17 +7,18 @@ ENV LANG=C.UTF-8 RUN dpkg --add-architecture i386 \ && apt-get update && apt-get upgrade -y \ && apt-get install -y --no-install-recommends \ - aria2 ca-certificates git less libmpc3 libncurses5 make \ + aria2 bash ca-certificates git less libmpc3 libncurses5 make \ ncurses-term perl-base python2-minimal wget xz-utils \ libc6:i386 zlib1g:i386 \ # the following packages are not required for rebuilding the stubs, but # they do make the image much more convenient and also allow building # the full UPX binary inside the container via CMake: - 7zip bfs bzip2 cmake curl elfutils fd-find file fzf g++ gdb gojq htop hyperfine \ - jq libzstd-dev lsb-release lzip lzop ninja-build p7zip patch patchelf pax-utils \ - ripgrep rsync screen universal-ctags unzip vim zip zlib1g-dev zsh zstd \ + 7zip bfs bzip2 chrpath cmake cpio curl elfutils fd-find file fzf g++ gdb gojq \ + ht htop hyperfine jq libzstd-dev lsb-release lz4 lzip lzop moreutils ninja-build \ + p7zip patch patchelf parallel pax-utils paxctl re2c ripgrep rsync \ + screen universal-ctags unzip vim zip zlib1g-dev zsh zstd \ # extra packages for compiling with "gcc -m32" and and "gcc -mx32": - gcc-multilib g++-multilib \ + g++-multilib gcc-multilib \ && true # manually install compat libs from Ubuntu 16.04; REQUIRED diff --git a/src/Makefile b/src/Makefile index 3ec380fa..b6d4ec10 100644 --- a/src/Makefile +++ b/src/Makefile @@ -80,8 +80,8 @@ endif ifeq ($(shell uname),Linux) # Markus loves clang-format, but John hates it; find a compromise CLANG_FORMAT_EXCLUDE_FILES += conf.h miniacc.h version.h help.cpp -CLANG_FORMAT_EXCLUDE_FILES += p_elf.h p_elf_enum.h p_lx_% p_mach% p_unix% p_vmli% -CLANG_FORMAT_EXCLUDE_FILES += packer_c.cpp packer_f.cpp +CLANG_FORMAT_EXCLUDE_FILES += p_elf.h p_elf_enum.h p_lx_% p_mach% p_unix% p_vmlin% +CLANG_FORMAT_EXCLUDE_FILES += packer_c.cpp CLANG_FORMAT_EXCLUDE_FILES += compress/compress.h filter/filter_impl.cpp CLANG_FORMAT_FILES := $(sort $(wildcard *.[ch]* ../maint/src/*.[ch]* [cu]*/*.[ch]*)) CLANG_FORMAT_FILES := $(filter-out $(CLANG_FORMAT_EXCLUDE_FILES),$(CLANG_FORMAT_FILES)) diff --git a/src/conf.h b/src/conf.h index 8244da8d..73177f0d 100644 --- a/src/conf.h +++ b/src/conf.h @@ -76,28 +76,32 @@ ACC_COMPILE_TIME_ASSERT_HEADER((-1) >> 31 == -1) // arithmetic right shift ACC_COMPILE_TIME_ASSERT_HEADER(CHAR_MAX == 255) // -funsigned-char ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char -// enable/disable some warnings +// enable some more strict warnings for Git developer builds +#if !UPX_CONFIG_DISABLE_WSTRICT && !UPX_CONFIG_DISABLE_WERROR #if (ACC_CC_CLANG >= 0x0b0000) # pragma clang diagnostic error "-Wsuggest-override" #elif (ACC_CC_GNUC >= 0x0a0000) // don't enable before gcc-10 because of gcc bug #78010 # pragma GCC diagnostic error "-Wsuggest-override" #endif +#if (ACC_CC_CLANG >= 0x050000) +# pragma clang diagnostic error "-Wzero-as-null-pointer-constant" +#elif (ACC_CC_GNUC >= 0x040700) && defined(__GLIBC__) // Some non-GLIBC toolchains do not use 'nullptr' everywhere when C++: // openwrt-sdk-x86-64_gcc-11.2.0_musl.Linux-x86_64/staging_dir/ // toolchain-x86_64_gcc-11.2.0_musl/include/fortify/stdlib.h: // 51:32: error: zero as null pointer constant -#if (ACC_CC_CLANG >= 0x050000) -# pragma clang diagnostic error "-Wzero-as-null-pointer-constant" -#elif (ACC_CC_GNUC >= 0x040700) && defined(__GLIBC__) # pragma GCC diagnostic error "-Wzero-as-null-pointer-constant" #endif - #if (ACC_CC_MSC) # pragma warning(error: 4127) # pragma warning(error: 4146) # pragma warning(error: 4319) # pragma warning(error: 4805) +#endif +#endif // !UPX_CONFIG_DISABLE_WSTRICT && !UPX_CONFIG_DISABLE_WERROR +// disable some warnings +#if (ACC_CC_MSC) # pragma warning(disable: 4244) // -Wconversion # pragma warning(disable: 4267) // -Wconversion # pragma warning(disable: 4820) // padding added after data member @@ -124,9 +128,17 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char // UPX currently does not use multithreading #define upx_std_atomic(Type) Type //#define upx_std_atomic(Type) typename std::add_volatile::type +#define upx_std_once_flag upx_std_atomic(size_t) +template +inline void upx_std_call_once(upx_std_once_flag &flag, NoexceptCallable &&f) { + if (!flag) { flag = 1; f(); } +} #else #include #define upx_std_atomic(Type) std::atomic +#include +#define upx_std_once_flag std::once_flag +#define upx_std_call_once std::call_once #endif // C++ submodule headers @@ -416,7 +428,7 @@ inline const T& UPX_MIN(const T& a, const T& b) { if (a < b) return a; return b; template struct USizeOfTypeImpl { static forceinline constexpr unsigned value() { - COMPILE_TIME_ASSERT(TypeSize >= 1 && TypeSize <= 64 * 1024); // arbitrary limit + COMPILE_TIME_ASSERT(TypeSize >= 1 && TypeSize <= 64 * 1024) // arbitrary limit return ACC_ICONV(unsigned, TypeSize); } }; diff --git a/src/except.cpp b/src/except.cpp index 53f4f982..a6681630 100644 --- a/src/except.cpp +++ b/src/except.cpp @@ -31,7 +31,7 @@ // **************************************************************************/ -unsigned long Throwable::counter = 0; +/*static*/ upx_std_atomic(size_t) Throwable::debug_counter; Throwable::Throwable(const char *m, int e, bool w) noexcept : super(), msg(nullptr), @@ -40,8 +40,8 @@ Throwable::Throwable(const char *m, int e, bool w) noexcept : super(), if (m) msg = strdup(m); #if 0 - fprintf(stderr, "construct exception: %s %lu\n", msg, counter); - counter++; + fprintf(stderr, "construct exception: %s %zu\n", msg, debug_counter); + debug_counter += 1; #endif } @@ -52,15 +52,15 @@ Throwable::Throwable(const Throwable &other) noexcept : super(other), if (other.msg) msg = strdup(other.msg); #if 0 - fprintf(stderr, "copy exception: %s %lu\n", msg, counter); - counter++; + fprintf(stderr, "copy exception: %s %zu\n", msg, debug_counter); + debug_counter += 1; #endif } Throwable::~Throwable() noexcept { #if 0 - counter--; - fprintf(stderr, "destruct exception: %s %lu\n", msg, counter); + debug_counter -= 1; + fprintf(stderr, "destruct exception: %s %zu\n", msg, debug_counter); #endif if (msg) free(msg); diff --git a/src/except.h b/src/except.h index b22edb4f..0e633d52 100644 --- a/src/except.h +++ b/src/except.h @@ -29,8 +29,6 @@ #ifndef UPX_EXCEPT_H__ #define UPX_EXCEPT_H__ 1 -#ifdef __cplusplus - const char *prettyName(const char *n) noexcept; /************************************************************************* @@ -64,7 +62,7 @@ private: ACC_CXX_DISABLE_NEW_DELETE private: - static unsigned long counter; // for debugging + static upx_std_atomic(size_t) debug_counter; // for debugging }; // Exceptions can/should be caught @@ -217,8 +215,6 @@ NORET void throwEOFException(const char *msg = nullptr, int e = 0); #undef NORET -#endif /* __cplusplus */ - #endif /* already included */ /* vim:set ts=4 sw=4 et: */ diff --git a/src/filter.cpp b/src/filter.cpp index af1da56a..b9e318e7 100644 --- a/src/filter.cpp +++ b/src/filter.cpp @@ -45,11 +45,11 @@ static void initFilter(Filter *f, upx_byte *buf, unsigned buf_len) { **************************************************************************/ const FilterImpl::FilterEntry *FilterImpl::getFilter(int id) { - static bool done = false; static unsigned char filter_map[256]; + static upx_std_once_flag init_done; - if (!done) { - // init the filter_map[] + upx_std_call_once(init_done, []() noexcept { + // init the filter_map[] (using a lambda function) assert(n_filters <= 254); // as 0xff means "empty slot" memset(filter_map, 0xff, sizeof(filter_map)); for (int i = 0; i < n_filters; i++) { @@ -58,8 +58,7 @@ const FilterImpl::FilterEntry *FilterImpl::getFilter(int id) { assert(filter_map[filter_id] == 0xff); filter_map[filter_id] = (unsigned char) i; } - done = true; - } + }); if (id < 0 || id > 255) return nullptr; @@ -103,7 +102,8 @@ void Filter::init(int id_, unsigned addvalue_) { this->n_mru = 0; } -bool Filter::filter(upx_byte *buf_, unsigned buf_len_) { +bool Filter::filter(SPAN_0(upx_byte) xbuf, unsigned buf_len_) { + upx_byte *const buf_ = raw_bytes(xbuf, buf_len_); initFilter(this, buf_, buf_len_); const FilterImpl::FilterEntry *const fe = FilterImpl::getFilter(id); @@ -134,7 +134,8 @@ bool Filter::filter(upx_byte *buf_, unsigned buf_len_) { return false; } -void Filter::unfilter(upx_byte *buf_, unsigned buf_len_, bool verify_checksum) { +void Filter::unfilter(SPAN_0(upx_byte) xbuf, unsigned buf_len_, bool verify_checksum) { + upx_byte *const buf_ = raw_bytes(xbuf, buf_len_); initFilter(this, buf_, buf_len_); const FilterImpl::FilterEntry *const fe = FilterImpl::getFilter(id); @@ -178,10 +179,11 @@ void Filter::verifyUnfilter() { unfilter(this->buf, this->buf_len, true); } -bool Filter::scan(const upx_byte *buf_, unsigned buf_len_) { +bool Filter::scan(SPAN_0(const upx_byte) xbuf, unsigned buf_len_) { + const upx_byte *const buf_ = raw_bytes(xbuf, buf_len_); // Note: must use const_cast here. This is fine as the scan // implementations (fe->do_scan) actually don't change the buffer. - upx_byte *b = const_cast(buf_); + upx_byte *const b = const_cast(buf_); initFilter(this, b, buf_len_); const FilterImpl::FilterEntry *const fe = FilterImpl::getFilter(id); diff --git a/src/filter.h b/src/filter.h index d0cc5c2a..0593544c 100644 --- a/src/filter.h +++ b/src/filter.h @@ -54,10 +54,10 @@ public: } void init(int id = 0, unsigned addvalue = 0); - bool filter(upx_byte *buf, unsigned buf_len); - void unfilter(upx_byte *buf, unsigned buf_len, bool verify_checksum = false); + bool filter(SPAN_0(upx_byte) buf, unsigned buf_len); + void unfilter(SPAN_0(upx_byte) buf, unsigned buf_len, bool verify_checksum = false); void verifyUnfilter(); - bool scan(const upx_byte *buf, unsigned buf_len); + bool scan(SPAN_0(const upx_byte) buf, unsigned buf_len); static bool isValidFilter(int filter_id); static bool isValidFilter(int filter_id, const int *allowed_filters); diff --git a/src/filter/filter_impl.cpp b/src/filter/filter_impl.cpp index b91b618d..8a4f730b 100644 --- a/src/filter/filter_impl.cpp +++ b/src/filter/filter_impl.cpp @@ -168,7 +168,7 @@ umin(unsigned const a, unsigned const b) // database for use in class Filter **************************************************************************/ -const FilterImpl::FilterEntry FilterImpl::filters[] = { +/*static*/ const FilterImpl::FilterEntry FilterImpl::filters[] = { // no filter { 0x00, 0, 0, nullptr, nullptr, nullptr }, @@ -261,6 +261,6 @@ const FilterImpl::FilterEntry FilterImpl::filters[] = { { 0xd0, 8, 0, f_ppcbxx, u_ppcbxx, s_ppcbxx }, }; -const int FilterImpl::n_filters = TABLESIZE(filters); +/*static*/ const int FilterImpl::n_filters = TABLESIZE(filters); /* vim:set ts=4 sw=4 et: */ diff --git a/src/p_armpe.cpp b/src/p_armpe.cpp index e2001299..15ef790b 100644 --- a/src/p_armpe.cpp +++ b/src/p_armpe.cpp @@ -46,6 +46,8 @@ PackArmPe::PackArmPe(InputFile *f) : super(f) {} PackArmPe::~PackArmPe() {} +Linker *PackArmPe::newLinker() const { return new ElfLinkerArmLE; } + const int *PackArmPe::getCompressionMethods(int method, int level) const { static const int m_all[] = {M_NRV2B_8, M_NRV2E_8, M_LZMA, M_END}; static const int m_lzma[] = {M_LZMA, M_END}; @@ -71,8 +73,6 @@ const int *PackArmPe::getFilters() const { return filters; } -Linker *PackArmPe::newLinker() const { return new ElfLinkerArmLE; } - /************************************************************************* // import handling **************************************************************************/ @@ -127,37 +127,37 @@ void PackArmPe::buildLoader(const Filter *ft) { initLoader(loader, size); if (isdll) - addLoader("DllStart", nullptr); - addLoader("ExeStart", nullptr); + addLoader("DllStart"); + addLoader("ExeStart"); if (ph.method == M_NRV2E_8) - addLoader("Call2E", nullptr); + addLoader("Call2E"); else if (ph.method == M_NRV2B_8) - addLoader("Call2B", nullptr); + addLoader("Call2B"); else if (ph.method == M_NRV2D_8) - addLoader("Call2D", nullptr); + addLoader("Call2D"); else if (M_IS_LZMA(ph.method)) - addLoader("+40C,CallLZMA", nullptr); + addLoader("+40C,CallLZMA"); if (ft->id == 0x50) - addLoader("+40C,Unfilter_0x50", nullptr); + addLoader("+40C,Unfilter_0x50"); if (sorelocs) - addLoader("+40C,Relocs", nullptr); + addLoader("+40C,Relocs"); - addLoader("+40C,Imports", nullptr); - addLoader("ProcessEnd", nullptr); + addLoader("+40C,Imports"); + addLoader("ProcessEnd"); if (ph.method == M_NRV2E_8) - addLoader(".ucl_nrv2e_decompress_8", nullptr); + addLoader(".ucl_nrv2e_decompress_8"); else if (ph.method == M_NRV2B_8) - addLoader(".ucl_nrv2b_decompress_8", nullptr); + addLoader(".ucl_nrv2b_decompress_8"); else if (ph.method == M_NRV2D_8) - addLoader(".ucl_nrv2d_decompress_8", nullptr); + addLoader(".ucl_nrv2d_decompress_8"); else if (M_IS_LZMA(ph.method)) - addLoader("+40C,LZMA_DECODE,LZMA_DEC10", nullptr); + addLoader("+40C,LZMA_DECODE,LZMA_DEC10"); - addLoader("IDENTSTR,UPX1HEAD", nullptr); + addLoader("IDENTSTR,UPX1HEAD"); } bool PackArmPe::handleForceOption() { diff --git a/src/p_com.cpp b/src/p_com.cpp index 99be6ef9..d60b1e35 100644 --- a/src/p_com.cpp +++ b/src/p_com.cpp @@ -1,4 +1,4 @@ -/* p_com.cpp -- +/* p_com.cpp -- dos/com executable format This file is part of the UPX executable compressor. @@ -35,23 +35,21 @@ static const CLANG_FORMAT_DUMMY_STATEMENT #include "stub/i086-dos16.com.h" -// #define TESTING 1 - /************************************************************************* // **************************************************************************/ +Linker *PackCom::newLinker() const { return new ElfLinkerX86(); } + const int *PackCom::getCompressionMethods(int method, int level) const { static const int m_nrv2b[] = {M_NRV2B_LE16, M_END}; -#if 0 - static const int m_nrv2d[] = { M_NRV2D_LE16, M_END }; -#endif UNUSED(method); UNUSED(level); return m_nrv2b; } const int *PackCom::getFilters() const { + // see class FilterImpl static const int filters[] = {0x06, 0x03, 0x04, 0x01, 0x05, 0x02, FT_END}; return filters; } @@ -64,16 +62,17 @@ bool PackCom::canPack() { unsigned char buf[128]; fi->readx(buf, sizeof(buf)); - if (memcmp(buf, "MZ", 2) == 0 || memcmp(buf, "ZM", 2) == 0 // .exe - || memcmp(buf, "\xff\xff\xff\xff", 4) == 0) // .sys + if (memcmp(buf, "MZ", 2) == 0 || memcmp(buf, "ZM", 2) == 0) // .exe return false; - if (!fn_has_ext(fi->getName(), "com")) + if (memcmp(buf, "\xff\xff\xff\xff", 4) == 0) // .sys + return false; + if (!fn_has_ext(fi->getName(), "com")) // query file name return false; checkAlreadyPacked(buf, sizeof(buf)); if (file_size < 1024) - throwCantPack("file is too small"); + throwCantPack("file is too small for dos/com"); if (file_size > 0xFF00) - throwCantPack("file is too big for dos/com"); + throwCantPack("file is too large for dos/com"); return true; } @@ -81,6 +80,49 @@ bool PackCom::canPack() { // **************************************************************************/ +void PackCom::addFilter16(int filter_id) { + assert(filter_id > 0); + assert(isValidFilter(filter_id)); + + if (filter_id % 3 == 0) { + // clang-format off + addLoader("CALLTR16", + filter_id < 4 ? "CT16SUB0" : "", + filter_id < 4 ? "" : (opt->cpu == opt->CPU_8086 ? "CT16I086" : "CT16I286,CT16SUB0"), + "CALLTRI2", + getFormat() == UPX_F_DOS_COM ? "CORETURN" : ""); + // clang-format on + } else { + // clang-format off + addLoader(filter_id % 3 == 1 ? "CT16E800" : "CT16E900", + "CALLTRI5", + getFormat() == UPX_F_DOS_COM ? "CT16JEND" : "CT16JUL2", + filter_id < 4 ? "CT16SUB1" : "", + filter_id < 4 ? "" : (opt->cpu == opt->CPU_8086 ? "CT16I087" : "CT16I287,CT16SUB1"), + "CALLTRI6"); + // clang-format on + } +} + +void PackCom::buildLoader(const Filter *ft) { + initLoader(stub_i086_dos16_com, sizeof(stub_i086_dos16_com)); + // clang-format off + addLoader("COMMAIN1", + ph.first_offset_found == 1 ? "COMSBBBP" : "", + "COMPSHDI", + ft->id ? "COMCALLT" : "", + "COMMAIN2,UPX1HEAD,COMCUTPO,NRV2B160", + ft->id ? "NRVDDONE" : "NRVDRETU", + "NRVDECO1", + ph.max_offset_found <= 0xd00 ? "NRVLED00" : "NRVGTD00", + "NRVDECO2"); + // clang-format on + if (ft->id) { + assert(ft->calls > 0); + addFilter16(ft->id); + } +} + void PackCom::patchLoader(OutputFile *fo, upx_byte *loader, int lsize, unsigned calls) { const int e_len = getLoaderSectionStart("COMCUTPO"); const int d_len = lsize - e_len; @@ -92,7 +134,7 @@ void PackCom::patchLoader(OutputFile *fo, upx_byte *loader, int lsize, unsigned if (upper_end + stacksize > 0xfffe) stacksize = 0x56; if (upper_end + stacksize > 0xfffe) - throwCantPack("file is too big for dos/com"); + throwCantPack("file is too large for dos/com"); linker->defineSymbol("calltrick_calls", calls); linker->defineSymbol("sp_limit", upper_end + stacksize); @@ -105,46 +147,15 @@ void PackCom::patchLoader(OutputFile *fo, upx_byte *loader, int lsize, unsigned relocateLoader(); loader = getLoader(); - // some day we could use the relocation stuff for patchPackHeader too + // some day we could use the relocation stuff for patchPackHeader too.. patchPackHeader(loader, e_len); // write loader + compressed file - fo->write(loader, e_len); // entry - fo->write(obuf, ph.c_len); + fo->write(loader, e_len); // entry + fo->write(obuf, ph.c_len); // compressed fo->write(loader + e_len, d_len); // decompressor -#if 0 - printf("%-13s: entry : %8ld bytes\n", getName(), (long) e_len); - printf("%-13s: compressed : %8ld bytes\n", getName(), (long) ph.c_len); - printf("%-13s: decompressor : %8ld bytes\n", getName(), (long) d_len); -#endif -} - -void PackCom::buildLoader(const Filter *ft) { - initLoader(stub_i086_dos16_com, sizeof(stub_i086_dos16_com)); - addLoader("COMMAIN1", ph.first_offset_found == 1 ? "COMSBBBP" : "", "COMPSHDI", - ft->id ? "COMCALLT" : "", "COMMAIN2,UPX1HEAD,COMCUTPO,NRV2B160", - ft->id ? "NRVDDONE" : "NRVDRETU", "NRVDECO1", - ph.max_offset_found <= 0xd00 ? "NRVLED00" : "NRVGTD00", "NRVDECO2", nullptr); - if (ft->id) { - assert(ft->calls > 0); - addFilter16(ft->id); - } -} - -void PackCom::addFilter16(int filter_id) { - assert(filter_id > 0); - assert(isValidFilter(filter_id)); - - if (filter_id % 3 == 0) - addLoader("CALLTR16", filter_id < 4 ? "CT16SUB0" : "", - filter_id < 4 ? "" - : (opt->cpu == opt->CPU_8086 ? "CT16I086" : "CT16I286,CT16SUB0"), - "CALLTRI2", getFormat() == UPX_F_DOS_COM ? "CORETURN" : "", nullptr); - else - addLoader( - filter_id % 3 == 1 ? "CT16E800" : "CT16E900", "CALLTRI5", - getFormat() == UPX_F_DOS_COM ? "CT16JEND" : "CT16JUL2", filter_id < 4 ? "CT16SUB1" : "", - filter_id < 4 ? "" : (opt->cpu == opt->CPU_8086 ? "CT16I087" : "CT16I287,CT16SUB1"), - "CALLTRI6", nullptr); + NO_printf("%-13s: entry : %8u bytes\n", getName(), e_len); + NO_printf("%-13s: compressed : %8u bytes\n", getName(), ph.c_len); + NO_printf("%-13s: decompressor : %8u bytes\n", getName(), d_len); } /************************************************************************* @@ -187,7 +198,7 @@ void PackCom::pack(OutputFile *fo) { **************************************************************************/ int PackCom::canUnpack() { - if (!readPackHeader(128)) + if (!readPackHeader(128)) // read "ph" return false; if (file_size_u <= ph.c_len) return false; @@ -224,6 +235,4 @@ void PackCom::unpack(OutputFile *fo) { fo->write(obuf, ph.u_len); } -Linker *PackCom::newLinker() const { return new ElfLinkerX86(); } - /* vim:set ts=4 sw=4 et: */ diff --git a/src/p_com.h b/src/p_com.h index a1acc3b1..ae604d9a 100644 --- a/src/p_com.h +++ b/src/p_com.h @@ -1,4 +1,4 @@ -/* p_com.h -- +/* p_com.h -- dos/com executable format This file is part of the UPX executable compressor. @@ -52,13 +52,12 @@ public: virtual int canUnpack() override; protected: - virtual unsigned getCallTrickOffset() const { return 0x100; } virtual Linker *newLinker() const override; - -protected: + void addFilter16(int filter_id); + // dos/sys will override these: + virtual unsigned getCallTrickOffset() const { return 0x100; } virtual void buildLoader(const Filter *ft) override; virtual void patchLoader(OutputFile *fo, upx_byte *, int, unsigned); - virtual void addFilter16(int filter_id); }; #endif /* already included */ diff --git a/src/p_djgpp2.cpp b/src/p_djgpp2.cpp index 3912bbe7..ebf94fce 100644 --- a/src/p_djgpp2.cpp +++ b/src/p_djgpp2.cpp @@ -54,6 +54,8 @@ PackDjgpp2::PackDjgpp2(InputFile *f) : super(f), coff_offset(0) { // assert(upx_adler32(stubify_stub, sizeof(stubify_stub)) == STUBIFY_STUB_ADLER32); } +Linker *PackDjgpp2::newLinker() const { return new ElfLinkerX86; } + const int *PackDjgpp2::getCompressionMethods(int method, int level) const { return Packer::getDefaultCompressionMethods_le32(method, level); } @@ -71,21 +73,19 @@ unsigned PackDjgpp2::findOverlapOverhead(const upx_bytep buf, const upx_bytep tb return o; } -Linker *PackDjgpp2::newLinker() const { return new ElfLinkerX86; } - void PackDjgpp2::buildLoader(const Filter *ft) { // prepare loader initLoader(stub_i386_dos32_djgpp2, sizeof(stub_i386_dos32_djgpp2)); addLoader("IDENTSTR,DJ2MAIN1", ft->id ? "DJCALLT1" : "", ph.first_offset_found == 1 ? "DJ2MAIN2" : "", M_IS_LZMA(ph.method) ? "LZMA_INIT_STACK" : "", getDecompressorSections(), - M_IS_LZMA(ph.method) ? "LZMA_DONE_STACK" : "", "DJ2BSS00", nullptr); + M_IS_LZMA(ph.method) ? "LZMA_DONE_STACK" : "", "DJ2BSS00"); if (ft->id) { assert(ft->calls > 0); - addLoader("DJCALLT2", nullptr); + addLoader("DJCALLT2"); addFilter32(ft->id); } - addLoader("DJRETURN,+40C,UPX1HEAD", nullptr); + addLoader("DJRETURN,+40C,UPX1HEAD"); } /************************************************************************* @@ -99,7 +99,7 @@ void PackDjgpp2::handleStub(OutputFile *fo) { Packer::handleStub(fi, fo, coff_offset); } else { // "stubify" stub - info("Adding stub: %ld bytes", (long) sizeof(stub_i386_dos32_djgpp2_stubify)); + info("Adding stub: %zd bytes", sizeof(stub_i386_dos32_djgpp2_stubify)); fo->write(stub_i386_dos32_djgpp2_stubify, sizeof(stub_i386_dos32_djgpp2_stubify)); } } @@ -179,9 +179,9 @@ int PackDjgpp2::readFileHeader() { return 0; // FIXME: check for Linux etc. - text = coff_hdr.sh; - data = text + 1; - bss = data + 1; + text = &coff_hdr.sh[0]; + data = &coff_hdr.sh[1]; + bss = &coff_hdr.sh[2]; return UPX_F_DJGPP2_COFF; } @@ -242,7 +242,7 @@ void PackDjgpp2::pack(OutputFile *fo) { // read file const unsigned size = text->size + data->size; const unsigned tpos = text->scnptr; - const unsigned hdrsize = 20 + 28 + sizeof(external_scnhdr_t) * coff_hdr.f_nscns; + const unsigned hdrsize = 20 + 28 + mem_size(sizeof(external_scnhdr_t), coff_hdr.f_nscns); const unsigned usize = size + hdrsize; if (hdrsize < sizeof(coff_hdr) || hdrsize > tpos) throwCantPack("coff header error"); @@ -371,11 +371,14 @@ void PackDjgpp2::unpack(OutputFile *fo) { // decompress decompress(ibuf, obuf); - coff_header_t *chdr = (coff_header_t *) obuf.getVoidPtr(); - text = chdr->sh; - data = text + 1; + coff_header_t *chdr = (coff_header_t *) raw_bytes(obuf, sizeof(coff_header_t)); + text = &chdr->sh[0]; + data = &chdr->sh[1]; + bss = &chdr->sh[2]; - const unsigned hdrsize = 20 + 28 + sizeof(external_scnhdr_t) * chdr->f_nscns; + const unsigned hdrsize = 20 + 28 + mem_size(sizeof(external_scnhdr_t), chdr->f_nscns); + if (hdrsize < sizeof(coff_hdr) || hdrsize > text->scnptr || hdrsize > ph.u_len) + throwCantUnpack("coff header error"); unsigned addvalue; if (ph.version >= 14) diff --git a/src/p_djgpp2.h b/src/p_djgpp2.h index 96ea2b10..f03f1feb 100644 --- a/src/p_djgpp2.h +++ b/src/p_djgpp2.h @@ -98,7 +98,9 @@ protected: }; coff_header_t coff_hdr; - external_scnhdr_t *text, *data, *bss; + external_scnhdr_t *text = nullptr; + external_scnhdr_t *data = nullptr; + external_scnhdr_t *bss = nullptr; void stripDebug(); }; diff --git a/src/p_exe.cpp b/src/p_exe.cpp index 4564672c..b5f4da76 100644 --- a/src/p_exe.cpp +++ b/src/p_exe.cpp @@ -1,4 +1,4 @@ -/* p_exe.cpp -- +/* p_exe.cpp -- dos/exe executable format This file is part of the UPX executable compressor. @@ -54,6 +54,8 @@ PackExe::PackExe(InputFile *f) : super(f) { use_clear_dirty_stack = false; } +Linker *PackExe::newLinker() const { return new ElfLinkerX86(); } + const int *PackExe::getCompressionMethods(int method, int level) const { bool small = ih_imagesize <= 256 * 1024; // disable lzma for "--brute" unless explicitly given "--lzma" @@ -106,16 +108,16 @@ int PackExe::fillExeHeader(struct exe_header_t *eh) const { } void PackExe::addLoaderEpilogue(int flag) { - addLoader("EXEMAIN5", nullptr); + addLoader("EXEMAIN5"); if (relocsize) addLoader(ph.u_len <= DI_LIMIT || (ph.u_len & 0x7fff) >= relocsize ? "EXENOADJ" : "EXEADJUS", "EXERELO1", has_9a ? "EXEREL9A" : "", "EXERELO2", - ih_exesize > 0xFE00 ? "EXEREBIG" : "", "EXERELO3", nullptr); + ih_exesize > 0xFE00 ? "EXEREBIG" : "", "EXERELO3"); addLoader("EXEMAIN8", device_driver ? "DEVICEEND" : "", (flag & SS) ? "EXESTACK" : "", - (flag & SP) ? "EXESTASP" : "", (flag & USEJUMP) ? "EXEJUMPF" : "", nullptr); + (flag & SP) ? "EXESTASP" : "", (flag & USEJUMP) ? "EXEJUMPF" : ""); if (!(flag & USEJUMP)) - addLoader(ih.cs ? "EXERCSPO" : "", "EXERETIP", nullptr); + addLoader(ih.cs ? "EXERCSPO" : "", "EXERETIP"); linker->defineSymbol("original_cs", ih.cs); linker->defineSymbol("original_ip", ih.ip); @@ -136,7 +138,7 @@ void PackExe::buildLoader(const Filter *) { if (M_IS_LZMA(ph.method)) { addLoader("LZMA_DEC00", opt->small ? "LZMA_DEC10" : "LZMA_DEC20", "LZMA_DEC30", use_clear_dirty_stack ? "LZMA_DEC31" : "", "LZMA_DEC32", - ph.u_len > 0xffff ? "LZMA_DEC33" : "", nullptr); + ph.u_len > 0xffff ? "LZMA_DEC33" : ""); addLoaderEpilogue(flag); defineDecompressorSymbols(); @@ -173,35 +175,35 @@ void PackExe::buildLoader(const Filter *) { initLoader(stub_i086_dos16_exe, sizeof(stub_i086_dos16_exe)); // prepare loader if (device_driver) - addLoader("DEVICEENTRY,LZMADEVICE,DEVICEENTRY2", nullptr); + addLoader("DEVICEENTRY,LZMADEVICE,DEVICEENTRY2"); linker->addSection("COMPRESSED_LZMA", compressed_lzma, c_len_lzma, 0); - addLoader("LZMAENTRY,NRV2B160,NRVDDONE,NRVDECO1,NRVGTD00,NRVDECO2", nullptr); + addLoader("LZMAENTRY,NRV2B160,NRVDDONE,NRVDECO1,NRVGTD00,NRVDECO2"); } else if (device_driver) - addLoader("DEVICEENTRY,DEVICEENTRY2", nullptr); + addLoader("DEVICEENTRY,DEVICEENTRY2"); addLoader("EXEENTRY", M_IS_LZMA(ph.method) && device_driver ? "LONGSUB" : "SHORTSUB", "JNCDOCOPY", relocsize ? "EXERELPU" : "", "EXEMAIN4", M_IS_LZMA(ph.method) ? "" : "EXEMAIN4B", "EXEMAIN4C", M_IS_LZMA(ph.method) ? "COMPRESSED_LZMA_START,COMPRESSED_LZMA" : "", - "+G5DXXXX,UPX1HEAD,EXECUTPO", nullptr); + "+G5DXXXX,UPX1HEAD,EXECUTPO"); if (ph.method == M_NRV2B_8) addLoader("NRV2B16S", // decompressor ph.u_len > DI_LIMIT ? "N2B64K01" : "", "NRV2BEX1", opt->cpu == opt->CPU_8086 ? "N2BX8601" : "N2B28601", "NRV2BEX2", opt->cpu == opt->CPU_8086 ? "N2BX8602" : "N2B28602", "NRV2BEX3", - ph.c_len > 0xffff ? "N2B64K02" : "", "NRV2BEX9", nullptr); + ph.c_len > 0xffff ? "N2B64K02" : "", "NRV2BEX9"); else if (ph.method == M_NRV2D_8) addLoader("NRV2D16S", ph.u_len > DI_LIMIT ? "N2D64K01" : "", "NRV2DEX1", opt->cpu == opt->CPU_8086 ? "N2DX8601" : "N2D28601", "NRV2DEX2", opt->cpu == opt->CPU_8086 ? "N2DX8602" : "N2D28602", "NRV2DEX3", - ph.c_len > 0xffff ? "N2D64K02" : "", "NRV2DEX9", nullptr); + ph.c_len > 0xffff ? "N2D64K02" : "", "NRV2DEX9"); else if (ph.method == M_NRV2E_8) addLoader("NRV2E16S", ph.u_len > DI_LIMIT ? "N2E64K01" : "", "NRV2EEX1", opt->cpu == opt->CPU_8086 ? "N2EX8601" : "N2E28601", "NRV2EEX2", opt->cpu == opt->CPU_8086 ? "N2EX8602" : "N2E28602", "NRV2EEX3", - ph.c_len > 0xffff ? "N2E64K02" : "", "NRV2EEX9", nullptr); + ph.c_len > 0xffff ? "N2E64K02" : "", "NRV2EEX9"); else if M_IS_LZMA (ph.method) return; else @@ -229,9 +231,7 @@ int PackExe::readFileHeader() { throwCantPack("illegal exe header"); if (file_size_u < ih_exesize || ih_imagesize <= 0 || ih_imagesize > ih_exesize) throwCantPack("exe header corrupted"); -#if 0 - printf("dos/exe header: %d %d %d\n", ih_exesize, ih_imagesize, ih_overlay); -#endif + NO_printf("dos/exe header: %d %d %d\n", ih_exesize, ih_imagesize, ih_overlay); return UPX_F_DOS_EXE; } @@ -553,13 +553,11 @@ void PackExe::pack(OutputFile *fo) { fo->write(loader + e_len, d_len); // decompressor fo->write(extra_info, eisize); assert(eisize <= 9); -#if 0 - printf("%-13s: program hdr : %8ld bytes\n", getName(), (long) sizeof(oh)); - printf("%-13s: entry : %8ld bytes\n", getName(), (long) e_len); - printf("%-13s: compressed : %8ld bytes\n", getName(), (long) packedsize); - printf("%-13s: decompressor : %8ld bytes\n", getName(), (long) d_len); - printf("%-13s: extra info : %8ld bytes\n", getName(), (long) eisize); -#endif + NO_printf("%-13s: program hdr : %8u bytes\n", getName(), usizeof(oh)); + NO_printf("%-13s: entry : %8u bytes\n", getName(), e_len); + NO_printf("%-13s: compressed : %8u bytes\n", getName(), packedsize); + NO_printf("%-13s: decompressor : %8u bytes\n", getName(), d_len); + NO_printf("%-13s: extra info : %8u bytes\n", getName(), eisize); // verify verifyOverlappingDecompression(); @@ -711,8 +709,6 @@ void PackExe::unpack(OutputFile *fo) { copyOverlay(fo, ih_overlay, obuf); } -Linker *PackExe::newLinker() const { return new ElfLinkerX86(); } - /* memory layout at decompression time diff --git a/src/p_exe.h b/src/p_exe.h index 62de1ffa..1bcbb370 100644 --- a/src/p_exe.h +++ b/src/p_exe.h @@ -1,4 +1,4 @@ -/* p_exe.h -- +/* p_exe.h -- dos/exe executable format This file is part of the UPX executable compressor. diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index e0d8cc4e..cd8fb6b1 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -30,6 +30,7 @@ */ +#define ALLOW_INT_PLUS_MEMBUFFER 1 #include "conf.h" #include "file.h" diff --git a/src/p_lx_sh.cpp b/src/p_lx_sh.cpp index 9478062e..08aab0ec 100644 --- a/src/p_lx_sh.cpp +++ b/src/p_lx_sh.cpp @@ -92,7 +92,7 @@ PackLinuxI386sh::buildLoader(Filter const *ft) optimizeFilter(&fold_ft, buf, sz_fold); unsigned fold_hdrlen = sizeof(l_info) + sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * get_te32(&((Elf32_Ehdr const *)(void *)buf)->e_phnum); - if (0 == get_le32(fold_hdrlen + buf)) { + if (0 == get_le32(buf + fold_hdrlen)) { // inconsistent SIZEOF_HEADERS in *.lds (ld, binutils) fold_hdrlen = umax(0x80, fold_hdrlen); } diff --git a/src/p_mach.cpp b/src/p_mach.cpp index 0c869ed7..6e8c6102 100644 --- a/src/p_mach.cpp +++ b/src/p_mach.cpp @@ -25,6 +25,7 @@ */ +#define ALLOW_INT_PLUS_MEMBUFFER 1 #include "conf.h" #include "file.h" diff --git a/src/p_sys.cpp b/src/p_sys.cpp index 14701975..3d49d84a 100644 --- a/src/p_sys.cpp +++ b/src/p_sys.cpp @@ -1,4 +1,4 @@ -/* p_sys.cpp -- +/* p_sys.cpp -- dos/sys executable format This file is part of the UPX executable compressor. @@ -46,13 +46,13 @@ bool PackSys::canPack() { fi->readx(buf, sizeof(buf)); if (memcmp(buf, "\xff\xff\xff\xff", 4) != 0) return false; - if (!fn_has_ext(fi->getName(), "sys")) + if (!fn_has_ext(fi->getName(), "sys")) // query file name return false; checkAlreadyPacked(buf, sizeof(buf)); if (file_size < 1024) - throwCantPack("file is too small"); + throwCantPack("file is too small for dos/sys"); if (file_size > 0x10000) - throwCantPack("file is too big for dos/sys"); + throwCantPack("file is too large for dos/sys"); return true; } @@ -60,6 +60,29 @@ bool PackSys::canPack() { // **************************************************************************/ +void PackSys::buildLoader(const Filter *ft) { + initLoader(stub_i086_dos16_sys, sizeof(stub_i086_dos16_sys)); + // clang-format off + addLoader("SYSMAIN1", + opt->cpu == opt->CPU_8086 ? "SYSI0861" : "SYSI2861", + "SYSMAIN2", + ph.first_offset_found == 1 ? "SYSSBBBP" : "", + ft->id ? "SYSCALLT" : "", + "SYSMAIN3,UPX1HEAD,SYSCUTPO,NRV2B160,NRVDDONE,NRVDECO1", + ph.max_offset_found <= 0xd00 ? "NRVLED00" : "NRVGTD00", + "NRVDECO2"); + // clang-format on + if (ft->id) { + assert(ft->calls > 0); + addFilter16(ft->id); + } + // clang-format off + addLoader("SYSMAIN5", + opt->cpu == opt->CPU_8086 ? "SYSI0862" : "SYSI2862", + "SYSJUMP1"); + // clang-format on +} + void PackSys::patchLoader(OutputFile *fo, upx_byte *loader, int lsize, unsigned calls) { const int e_len = getLoaderSectionStart("SYSCUTPO"); const int d_len = lsize - e_len; @@ -85,24 +108,15 @@ void PackSys::patchLoader(OutputFile *fo, upx_byte *loader, int lsize, unsigned relocateLoader(); loader = getLoader(); + // some day we could use the relocation stuff for patchPackHeader too.. patchPackHeader(loader, e_len); // write loader + compressed file - fo->write(loader, e_len); // entry - fo->write(obuf, ph.c_len); + fo->write(loader, e_len); // entry + fo->write(obuf, ph.c_len); // compressed fo->write(loader + e_len, d_len); // decompressor -} - -void PackSys::buildLoader(const Filter *ft) { - initLoader(stub_i086_dos16_sys, sizeof(stub_i086_dos16_sys)); - addLoader("SYSMAIN1", opt->cpu == opt->CPU_8086 ? "SYSI0861" : "SYSI2861", "SYSMAIN2", - ph.first_offset_found == 1 ? "SYSSBBBP" : "", ft->id ? "SYSCALLT" : "", - "SYSMAIN3,UPX1HEAD,SYSCUTPO,NRV2B160,NRVDDONE,NRVDECO1", - ph.max_offset_found <= 0xd00 ? "NRVLED00" : "NRVGTD00", "NRVDECO2", nullptr); - if (ft->id) { - assert(ft->calls > 0); - addFilter16(ft->id); - } - addLoader("SYSMAIN5", opt->cpu == opt->CPU_8086 ? "SYSI0862" : "SYSI2862", "SYSJUMP1", nullptr); + NO_printf("%-13s: entry : %8u bytes\n", getName(), e_len); + NO_printf("%-13s: compressed : %8u bytes\n", getName(), ph.c_len); + NO_printf("%-13s: decompressor : %8u bytes\n", getName(), d_len); } /* vim:set ts=4 sw=4 et: */ diff --git a/src/p_sys.h b/src/p_sys.h index 8c23f5ac..e68e120b 100644 --- a/src/p_sys.h +++ b/src/p_sys.h @@ -1,4 +1,4 @@ -/* p_sys.h -- +/* p_sys.h -- dos/sys executable format This file is part of the UPX executable compressor. @@ -45,10 +45,8 @@ public: virtual bool canPack() override; -protected: +protected: // dos/com overrides virtual unsigned getCallTrickOffset() const override { return 0; } - -protected: virtual void buildLoader(const Filter *ft) override; virtual void patchLoader(OutputFile *fo, upx_byte *, int, unsigned) override; }; diff --git a/src/p_tmt.cpp b/src/p_tmt.cpp index 72eb1c03..ee303478 100644 --- a/src/p_tmt.cpp +++ b/src/p_tmt.cpp @@ -46,6 +46,8 @@ PackTmt::PackTmt(InputFile *f) : super(f) { COMPILE_TIME_ASSERT(sizeof(tmt_header_t) == 44) } +Linker *PackTmt::newLinker() const { return new ElfLinkerX86; } + const int *PackTmt::getCompressionMethods(int method, int level) const { return Packer::getDefaultCompressionMethods_le32(method, level); } @@ -64,24 +66,22 @@ unsigned PackTmt::findOverlapOverhead(const upx_bytep buf, const upx_bytep tbuf, return o; } -Linker *PackTmt::newLinker() const { return new ElfLinkerX86; } - void PackTmt::buildLoader(const Filter *ft) { // prepare loader initLoader(stub_i386_dos32_tmt, sizeof(stub_i386_dos32_tmt)); addLoader("IDENTSTR,TMTMAIN1", ph.first_offset_found == 1 ? "TMTMAIN1A" : "", "TMTMAIN1B", - ft->id ? "TMTCALT1" : "", "TMTMAIN2,UPX1HEAD,TMTCUTPO", nullptr); + ft->id ? "TMTCALT1" : "", "TMTMAIN2,UPX1HEAD,TMTCUTPO"); // fake alignment for the start of the decompressor linker->defineSymbol("TMTCUTPO", 0x1000); - addLoader(getDecompressorSections(), "TMTMAIN5", nullptr); + addLoader(getDecompressorSections(), "TMTMAIN5"); if (ft->id) { assert(ft->calls > 0); - addLoader("TMTCALT2", nullptr); + addLoader("TMTCALT2"); addFilter32(ft->id); } - addLoader("TMTRELOC,RELOC320", big_relocs ? "REL32BIG" : "", "RELOC32J,TMTJUMP1", nullptr); + addLoader("TMTRELOC,RELOC320", big_relocs ? "REL32BIG" : "", "RELOC32J,TMTJUMP1"); } /************************************************************************* @@ -139,8 +139,8 @@ int PackTmt::readFileHeader() { unsigned const imagesize = ih.imagesize; unsigned const entry = ih.entry; unsigned const relocsize = ih.relocsize; - if (imagesize < sizeof(ih) || entry < sizeof(ih) || file_size <= imagesize || - file_size <= entry || file_size <= relocsize) { + if (imagesize < sizeof(ih) || entry < sizeof(ih) || file_size_u <= imagesize || + file_size_u <= entry || file_size_u <= relocsize) { printWarn(getName(), "bad header; imagesize=%#x entry=%#x relocsize=%#x", imagesize, entry, relocsize); return 0; @@ -202,7 +202,7 @@ void PackTmt::pack(OutputFile *fo) { relocsize += 4; set_le32(wrkmem + relocsize, relocsize + 4); relocsize += 4; - memcpy(ibuf + usize, wrkmem, relocsize); + memcpy(raw_index_bytes(ibuf, usize, relocsize), wrkmem, relocsize); // prepare packheader ph.u_len = usize + relocsize; diff --git a/src/p_tos.cpp b/src/p_tos.cpp index edfab51a..3da7eaa2 100644 --- a/src/p_tos.cpp +++ b/src/p_tos.cpp @@ -50,6 +50,8 @@ PackTos::PackTos(InputFile *f) : super(f) { COMPILE_TIME_ASSERT_ALIGNED1(tos_header_t) } +Linker *PackTos::newLinker() const { return new ElfLinkerM68k; } + const int *PackTos::getCompressionMethods(int method, int level) const { bool small = ih.fh_text + ih.fh_data <= 256 * 1024; return Packer::getDefaultCompressionMethods_8(method, level, small); @@ -57,8 +59,6 @@ const int *PackTos::getCompressionMethods(int method, int level) const { const int *PackTos::getFilters() const { return nullptr; } -Linker *PackTos::newLinker() const { return new ElfLinkerM68k; } - void PackTos::LinkerSymbols::LoopInfo::init(unsigned count_, bool allow_dbra) { count = value = count_; if (count == 0) diff --git a/src/p_vmlinz.cpp b/src/p_vmlinz.cpp index 79cf5249..c7aadf8b 100644 --- a/src/p_vmlinz.cpp +++ b/src/p_vmlinz.cpp @@ -26,6 +26,7 @@ */ +#define ALLOW_INT_PLUS_MEMBUFFER 1 #include "conf.h" #include "p_elf.h" diff --git a/src/p_w32pe.cpp b/src/p_w32pe.cpp index c7991da2..7643db7b 100644 --- a/src/p_w32pe.cpp +++ b/src/p_w32pe.cpp @@ -98,44 +98,44 @@ void PackW32Pe::buildLoader(const Filter *ft) { tmp_tlsindex ? "PETLSHAK" : "", "PEMAIN02", ph.first_offset_found == 1 ? "PEMAIN03" : "", getDecompressorSections(), // multipass ? "PEMULTIP" : "", - "PEMAIN10", nullptr); + "PEMAIN10"); addLoader(tmp_tlsindex ? "PETLSHAK2" : ""); if (ft->id) { const unsigned texv = ih.codebase - rvamin; assert(ft->calls > 0); - addLoader(texv ? "PECTTPOS" : "PECTTNUL", nullptr); + addLoader(texv ? "PECTTPOS" : "PECTTNUL"); addFilter32(ft->id); } if (soimport) addLoader("PEIMPORT", importbyordinal ? "PEIBYORD" : "", kernel32ordinal ? "PEK32ORD" : "", importbyordinal ? "PEIMORD1" : "", "PEIMPOR2", isdll ? "PEIERDLL" : "PEIEREXE", - "PEIMDONE", nullptr); + "PEIMDONE"); if (sorelocs) { addLoader(soimport == 0 || soimport + cimports != crelocs ? "PERELOC1" : "PERELOC2", - "PERELOC3,RELOC320", big_relocs ? "REL32BIG" : "", "RELOC32J", nullptr); + "PERELOC3,RELOC320", big_relocs ? "REL32BIG" : "", "RELOC32J"); // FIXME: the following should be moved out of the above if addLoader(big_relocs & 6 ? "PERLOHI0" : "", big_relocs & 4 ? "PERELLO0" : "", - big_relocs & 2 ? "PERELHI0" : "", nullptr); + big_relocs & 2 ? "PERELHI0" : ""); } if (use_dep_hack) - addLoader("PEDEPHAK", nullptr); + addLoader("PEDEPHAK"); // NEW: TLS callback support PART 1, the callback handler installation - Stefan Widmann if (use_tls_callbacks) - addLoader("PETLSC", nullptr); + addLoader("PETLSC"); - addLoader("PEMAIN20", nullptr); + addLoader("PEMAIN20"); if (use_clear_dirty_stack) - addLoader("CLEARSTACK", nullptr); - addLoader("PEMAIN21", nullptr); + addLoader("CLEARSTACK"); + addLoader("PEMAIN21"); // NEW: last loader sections split up to insert TLS callback handler - Stefan Widmann - addLoader(ih.entry || !ilinker ? "PEDOJUMP" : "PERETURN", nullptr); + addLoader(ih.entry || !ilinker ? "PEDOJUMP" : "PERETURN"); // NEW: TLS callback support PART 2, the callback handler - Stefan Widmann if (use_tls_callbacks) - addLoader("PETLSC2", nullptr); + addLoader("PETLSC2"); - addLoader("IDENTSTR,UPX1HEAD", nullptr); + addLoader("IDENTSTR,UPX1HEAD"); } bool PackW32Pe::handleForceOption() { diff --git a/src/p_w64pep.cpp b/src/p_w64pep.cpp index e6c6af4d..b885e915 100644 --- a/src/p_w64pep.cpp +++ b/src/p_w64pep.cpp @@ -97,49 +97,49 @@ void PackW64Pep::buildLoader(const Filter *ft) { : M_IS_NRV2E(ph.method) ? "NRV_HEAD,NRV2E" : "UNKNOWN_COMPRESSION_METHOD", // getDecompressorSections(), - /*multipass ? "PEMULTIP" : */ "", "PEMAIN10", nullptr); + /*multipass ? "PEMULTIP" : */ "", "PEMAIN10"); addLoader(tmp_tlsindex ? "PETLSHAK2" : ""); if (ft->id) { const unsigned texv = ih.codebase - rvamin; assert(ft->calls > 0); - addLoader(texv ? "PECTTPOS" : "PECTTNUL", nullptr); + addLoader(texv ? "PECTTPOS" : "PECTTNUL"); addLoader("PEFILTER49"); } if (soimport) addLoader("PEIMPORT", importbyordinal ? "PEIBYORD" : "", kernel32ordinal ? "PEK32ORD" : "", importbyordinal ? "PEIMORD1" : "", "PEIMPOR2", isdll ? "PEIERDLL" : "PEIEREXE", - "PEIMDONE", nullptr); + "PEIMDONE"); if (sorelocs) { addLoader(soimport == 0 || soimport + cimports != crelocs ? "PERELOC1" : "PERELOC2", - "PERELOC3", big_relocs ? "REL64BIG" : "", "RELOC64J", nullptr); + "PERELOC3", big_relocs ? "REL64BIG" : "", "RELOC64J"); if __acc_cte (0) { addLoader(big_relocs & 6 ? "PERLOHI0" : "", big_relocs & 4 ? "PERELLO0" : "", - big_relocs & 2 ? "PERELHI0" : "", nullptr); + big_relocs & 2 ? "PERELHI0" : ""); } } if (use_dep_hack) - addLoader("PEDEPHAK", nullptr); + addLoader("PEDEPHAK"); // NEW: TLS callback support PART 1, the callback handler installation - Stefan Widmann if (use_tls_callbacks) - addLoader("PETLSC", nullptr); + addLoader("PETLSC"); - addLoader("PEMAIN20", nullptr); + addLoader("PEMAIN20"); if (use_clear_dirty_stack) - addLoader("CLEARSTACK", nullptr); - addLoader("PEMAIN21", nullptr); + addLoader("CLEARSTACK"); + addLoader("PEMAIN21"); if (ih.entry && isdll) addLoader("PEISDLL9"); if (isefi) addLoader("PEISEFI9"); - addLoader(ih.entry || !ilinker ? "PEDOJUMP" : "PERETURN", nullptr); + addLoader(ih.entry || !ilinker ? "PEDOJUMP" : "PERETURN"); // NEW: TLS callback support PART 2, the callback handler - Stefan Widmann if (use_tls_callbacks) - addLoader("PETLSC2", nullptr); + addLoader("PETLSC2"); - addLoader("IDENTSTR,UPX1HEAD", nullptr); + addLoader("IDENTSTR,UPX1HEAD"); } bool PackW64Pep::handleForceOption() { diff --git a/src/p_wcle.cpp b/src/p_wcle.cpp index 3ee169fd..db4450fa 100644 --- a/src/p_wcle.cpp +++ b/src/p_wcle.cpp @@ -85,22 +85,22 @@ void PackWcle::buildLoader(const Filter *ft) { // prepare loader initLoader(stub_i386_dos32_watcom_le, sizeof(stub_i386_dos32_watcom_le)); addLoader("IDENTSTR,WCLEMAIN", ph.first_offset_found == 1 ? "WCLEMAIN02" : "", - "WCLEMAIN03,UPX1HEAD,WCLECUTP", nullptr); + "WCLEMAIN03,UPX1HEAD,WCLECUTP"); // fake alignment for the start of the decompressor linker->defineSymbol("WCLECUTP", 0x1000); - addLoader(getDecompressorSections(), "WCLEMAI2", nullptr); + addLoader(getDecompressorSections(), "WCLEMAI2"); if (ft->id) { assert(ft->calls > 0); - addLoader(ft->addvalue ? "WCCTTPOS" : "WCCTTNUL", nullptr); + addLoader(ft->addvalue ? "WCCTTPOS" : "WCCTTNUL"); addFilter32(ft->id); } #if 1 // FIXME: if (has_relocation) - { addLoader("WCRELOC1,RELOC320", big_relocs ? "REL32BIG" : "", "RELOC32J", nullptr); } + { addLoader("WCRELOC1,RELOC320", big_relocs ? "REL32BIG" : "", "RELOC32J"); } #endif - addLoader(has_extra_code ? "WCRELSEL" : "", "WCLEMAI4", nullptr); + addLoader(has_extra_code ? "WCRELSEL" : "", "WCLEMAI4"); } /************************************************************************* diff --git a/src/packer.cpp b/src/packer.cpp index 06489549..dbfb49fe 100644 --- a/src/packer.cpp +++ b/src/packer.cpp @@ -1270,9 +1270,11 @@ void Packer::compressWithFilters(upx_bytep i_ptr, assert(nfilters < 256); #if 0 printf("compressWithFilters: m(%d):", nmethods); - for (int i = 0; i < nmethods; i++) printf(" %#x", methods[i]); + for (int i = 0; i < nmethods; i++) + printf(" %#x", methods[i]); printf(" f(%d):", nfilters); - for (int i = 0; i < nfilters; i++) printf(" %#x", filters[i]); + for (int i = 0; i < nfilters; i++) + printf(" %#x", filters[i]); printf("\n"); #endif @@ -1294,9 +1296,7 @@ void Packer::compressWithFilters(upx_bytep i_ptr, int nfilters_success_total = 0; for (int mm = 0; mm < nmethods; mm++) // for all methods { -#if 0 //{ - printf("\nmethod %d (%d of %d)\n", methods[mm], 1+ mm, nmethods); -#endif //} + NO_printf("\nmethod %d (%d of %d)\n", methods[mm], 1 + mm, nmethods); assert(isValidCompressionMethod(methods[mm])); unsigned hdr_c_len = 0; if (hdr_ptr != nullptr && hdr_len) { @@ -1341,10 +1341,9 @@ void Packer::compressWithFilters(upx_bytep i_ptr, continue; } // filter success -#if 0 - printf("\nfilter: id 0x%02x size %6d, calls %5d/%5d/%3d/%5d/%5d, cto 0x%02x\n", - ft.id, ft.buf_len, ft.calls, ft.noncalls, ft.wrongcalls, ft.firstcall, ft.lastcall, ft.cto); -#endif + NO_printf("\nfilter: id 0x%02x size %6d, calls %5d/%5d/%3d/%5d/%5d, cto 0x%02x\n", + ft.id, ft.buf_len, ft.calls, ft.noncalls, ft.wrongcalls, ft.firstcall, + ft.lastcall, ft.cto); if (nfilters_success_total != 0 && o_tmp == o_ptr) { o_tmp_buf.allocForCompression(i_len); o_tmp = o_tmp_buf; @@ -1365,11 +1364,10 @@ void Packer::compressWithFilters(upx_bytep i_ptr, lsize = getLoaderSize(); assert(lsize > 0); } -#if 0 //{ - printf("\n%2d %02x: %d +%4d +%3d = %d (best: %d +%4d +%3d = %d)\n", ph.method, ph.filter, - ph.c_len, lsize, hdr_c_len, ph.c_len + lsize + hdr_c_len, - best_ph.c_len, best_ph_lsize, best_hdr_c_len, best_ph.c_len + best_ph_lsize + best_hdr_c_len); -#endif //} + NO_printf("\n%2d %02x: %d +%4d +%3d = %d (best: %d +%4d +%3d = %d)\n", ph.method, + ph.filter, ph.c_len, lsize, hdr_c_len, ph.c_len + lsize + hdr_c_len, + best_ph.c_len, best_ph_lsize, best_hdr_c_len, + best_ph.c_len + best_ph_lsize + best_hdr_c_len); bool update = false; if (ph.c_len + lsize + hdr_c_len < best_ph.c_len + best_ph_lsize + best_hdr_c_len) update = true; diff --git a/src/packer.h b/src/packer.h index a82ced90..25cd553e 100644 --- a/src/packer.h +++ b/src/packer.h @@ -34,7 +34,6 @@ class InputFile; class OutputFile; class Packer; -class PackMaster; class UiPacker; class Filter; diff --git a/src/packer_c.cpp b/src/packer_c.cpp index cb554bb5..5df6acfb 100644 --- a/src/packer_c.cpp +++ b/src/packer_c.cpp @@ -25,12 +25,9 @@ */ - #include "conf.h" #include "packer.h" #include "linker.h" -//#include "filter.h" - /************************************************************************* // compression method util @@ -40,7 +37,7 @@ bool Packer::isValidCompressionMethod(int method) { if (M_IS_LZMA(method)) return true; - return (method >= M_NRV2B_LE32 && method <= M_LZMA); + return method >= M_NRV2B_LE32 && method <= M_LZMA; } diff --git a/src/packer_f.cpp b/src/packer_f.cpp index 36238f7e..e3564cd9 100644 --- a/src/packer_f.cpp +++ b/src/packer_f.cpp @@ -25,282 +25,240 @@ */ - #include "conf.h" #include "packer.h" #include "filter.h" #include "linker.h" - /************************************************************************* -// filter util +// filter util; see class FilterImpl **************************************************************************/ -bool Packer::isValidFilter(int filter_id) const -{ +bool Packer::isValidFilter(int filter_id) const { return Filter::isValidFilter(filter_id, getFilters()); } - /************************************************************************* // addFilter32 **************************************************************************/ -#define NOFILT 0 // no filter -#define FNOMRU 1 // filter, but not using mru -#define MRUFLT 2 // mru filter +#define NOFILT 0 // no filter +#define FNOMRU 1 // filter, but not using mru +#define MRUFLT 2 // mru filter -static inline unsigned f80_call(int filter_id) -{ - return (1+ (0x0f & filter_id)) % 3; -} +static inline unsigned f80_call(int filter_id) { return (1 + (0x0f & filter_id)) % 3; } -static inline unsigned f80_jmp1(int filter_id) -{ - return ((1+ (0x0f & filter_id)) / 3) % 3; -} +static inline unsigned f80_jmp1(int filter_id) { return ((1 + (0x0f & filter_id)) / 3) % 3; } -static inline unsigned f80_jcc2(int filter_id) -{ - return f80_jmp1(filter_id); -} +static inline unsigned f80_jcc2(int filter_id) { return f80_jmp1(filter_id); } - -void Packer::addFilter32(int filter_id) -{ +void Packer::addFilter32(int filter_id) { assert(filter_id > 0); assert(isValidFilter(filter_id)); if (filter_id < 0x80) { - if (0x50==(0xF0 & filter_id)) { + if (0x50 == (0xF0 & filter_id)) { addLoader("ctok32.00", - ((0x50==filter_id) ? "ctok32.50" : - (0x51==filter_id) ? "ctok32.51" : ""), - "ctok32.10", nullptr); - } - else if ((filter_id & 0xf) % 3 == 0) { + ((0x50 == filter_id) ? "ctok32.50" + : (0x51 == filter_id) ? "ctok32.51" + : ""), + "ctok32.10"); + } else if ((filter_id & 0xf) % 3 == 0) { if (filter_id < 0x40) { - addLoader("CALLTR00", - (filter_id > 0x20) ? "CTCLEVE1" : "", - "CALLTR01", - (filter_id & 0xf) > 3 ? (filter_id > 0x20 ? "CTBSHR01,CTBSWA01" : "CTBROR01,CTBSWA01") : "", - "CALLTR02", - nullptr - ); - } - else if (0x40==(0xF0 & filter_id)) { - addLoader("ctok32.00", nullptr); - if (9<=(0xf & filter_id)) { - addLoader("ctok32.10", nullptr); + addLoader("CALLTR00", (filter_id > 0x20) ? "CTCLEVE1" : "", "CALLTR01", + (filter_id & 0xf) > 3 + ? (filter_id > 0x20 ? "CTBSHR01,CTBSWA01" : "CTBROR01,CTBSWA01") + : "", + "CALLTR02"); + } else if (0x40 == (0xF0 & filter_id)) { + addLoader("ctok32.00"); + if (9 <= (0xf & filter_id)) { + addLoader("ctok32.10"); } - addLoader("ctok32.20", nullptr); - if (9<=(0xf & filter_id)) { - addLoader("ctok32.30", nullptr); + addLoader("ctok32.20"); + if (9 <= (0xf & filter_id)) { + addLoader("ctok32.30"); } - addLoader("ctok32.40", nullptr); + addLoader("ctok32.40"); } - } - else - addLoader("CALLTR10", - (filter_id & 0xf) % 3 == 1 ? "CALLTRE8" : "CALLTRE9", - "CALLTR11", - (filter_id > 0x20) ? "CTCLEVE2" : "", - "CALLTR12", - (filter_id & 0xf) > 3 ? (filter_id > 0x20 ? "CTBSHR11,CTBSWA11" : "CTBROR11,CTBSWA11") : "", - "CALLTR13", - nullptr - ); + } else + addLoader("CALLTR10", (filter_id & 0xf) % 3 == 1 ? "CALLTRE8" : "CALLTRE9", "CALLTR11", + (filter_id > 0x20) ? "CTCLEVE2" : "", "CALLTR12", + (filter_id & 0xf) > 3 + ? (filter_id > 0x20 ? "CTBSHR11,CTBSWA11" : "CTBROR11,CTBSWA11") + : "", + "CALLTR13"); } - if (0x80==(filter_id & 0xF0)) { + if (0x80 == (filter_id & 0xF0)) { bool const x386 = (opt->cpu <= opt->CPU_386); - unsigned const n_mru = ph.n_mru ? 1+ ph.n_mru : 0; - bool const mrupwr2 = (0!=n_mru) && 0==((n_mru -1) & n_mru); + unsigned const n_mru = ph.n_mru ? 1 + ph.n_mru : 0; + bool const mrupwr2 = (0 != n_mru) && 0 == ((n_mru - 1) & n_mru); unsigned const f_call = f80_call(filter_id); unsigned const f_jmp1 = f80_jmp1(filter_id); unsigned const f_jcc2 = f80_jcc2(filter_id); - if (NOFILT!=f_jcc2) { - addLoader("LXJCC010", nullptr); - if (n_mru) { - addLoader("LXMRU045", nullptr); - } - else { - addLoader("LXMRU046", nullptr); - } - if (0==n_mru || MRUFLT!=f_jcc2) { - addLoader("LXJCC020", nullptr); - } - else { // 0!=n_mru - addLoader("LXJCC021", nullptr); - } - if (NOFILT!=f_jcc2) { - addLoader("LXJCC023", nullptr); - } + if (NOFILT != f_jcc2) { + addLoader("LXJCC010"); + if (n_mru) { + addLoader("LXMRU045"); + } else { + addLoader("LXMRU046"); + } + if (0 == n_mru || MRUFLT != f_jcc2) { + addLoader("LXJCC020"); + } else { // 0 != n_mru + addLoader("LXJCC021"); + } + if (NOFILT != f_jcc2) { + addLoader("LXJCC023"); + } } - addLoader("LXUNF037", nullptr); + addLoader("LXUNF037"); if (x386) { if (n_mru) { - addLoader("LXUNF386", nullptr); + addLoader("LXUNF386"); } - addLoader("LXUNF387", nullptr); + addLoader("LXUNF387"); if (n_mru) { - addLoader("LXUNF388", nullptr); + addLoader("LXUNF388"); } - } - else { - addLoader("LXUNF486", nullptr); + } else { + addLoader("LXUNF486"); if (n_mru) { - addLoader("LXUNF487", nullptr); + addLoader("LXUNF487"); } } if (n_mru) { - addLoader("LXMRU065", nullptr); - if (256==n_mru) { - addLoader("MRUBYTE3", nullptr); - } - else { - addLoader("MRUARB30", nullptr); + addLoader("LXMRU065"); + if (256 == n_mru) { + addLoader("MRUBYTE3"); + } else { + addLoader("MRUARB30"); if (mrupwr2) { - addLoader("MRUBITS3", nullptr); - } - else { - addLoader("MRUARB40", nullptr); + addLoader("MRUBITS3"); + } else { + addLoader("MRUARB40"); } } - addLoader("LXMRU070", nullptr); - if (256==n_mru) { - addLoader("MRUBYTE4", nullptr); + addLoader("LXMRU070"); + if (256 == n_mru) { + addLoader("MRUBYTE4"); + } else if (mrupwr2) { + addLoader("MRUBITS4"); + } else { + addLoader("MRUARB50"); } - else if (mrupwr2) { - addLoader("MRUBITS4", nullptr); - } - else { - addLoader("MRUARB50", nullptr); - } - addLoader("LXMRU080", nullptr); - if (256==n_mru) { - addLoader("MRUBYTE5", nullptr); - } - else { - addLoader("MRUARB60", nullptr); + addLoader("LXMRU080"); + if (256 == n_mru) { + addLoader("MRUBYTE5"); + } else { + addLoader("MRUARB60"); if (mrupwr2) { - addLoader("MRUBITS5", nullptr); - } - else { - addLoader("MRUARB70", nullptr); + addLoader("MRUBITS5"); + } else { + addLoader("MRUARB70"); } } - addLoader("LXMRU090", nullptr); - if (256==n_mru) { - addLoader("MRUBYTE6", nullptr); - } - else { - addLoader("MRUARB80", nullptr); + addLoader("LXMRU090"); + if (256 == n_mru) { + addLoader("MRUBYTE6"); + } else { + addLoader("MRUARB80"); if (mrupwr2) { - addLoader("MRUBITS6", nullptr); - } - else { - addLoader("MRUARB90", nullptr); + addLoader("MRUBITS6"); + } else { + addLoader("MRUARB90"); } } - addLoader("LXMRU100", nullptr); + addLoader("LXMRU100"); } - addLoader("LXUNF040", nullptr); + addLoader("LXUNF040"); if (n_mru) { - addLoader("LXMRU110", nullptr); + addLoader("LXMRU110"); + } else { + addLoader("LXMRU111"); } - else { - addLoader("LXMRU111", nullptr); - } - addLoader("LXUNF041", nullptr); - addLoader("LXUNF042", nullptr); + addLoader("LXUNF041"); + addLoader("LXUNF042"); if (n_mru) { - addLoader("LXMRU010", nullptr); - if (NOFILT!=f_jmp1 && NOFILT==f_call) { - addLoader("LXJMPA00", nullptr); + addLoader("LXMRU010"); + if (NOFILT != f_jmp1 && NOFILT == f_call) { + addLoader("LXJMPA00"); + } else { + addLoader("LXCALLB0"); } - else { - addLoader("LXCALLB0", nullptr); - } - addLoader("LXUNF021", nullptr); - } - else { - addLoader("LXMRU022", nullptr); - if (NOFILT!=f_jmp1 && NOFILT==f_call) { - addLoader("LXJMPA01", nullptr); - } - else { - addLoader("LXCALLB1", nullptr); + addLoader("LXUNF021"); + } else { + addLoader("LXMRU022"); + if (NOFILT != f_jmp1 && NOFILT == f_call) { + addLoader("LXJMPA01"); + } else { + addLoader("LXCALLB1"); } } if (n_mru) { - if (256!=n_mru && mrupwr2) { - addLoader("MRUBITS1", nullptr); + if (256 != n_mru && mrupwr2) { + addLoader("MRUBITS1"); } - addLoader("LXMRU030", nullptr); - if (256==n_mru) { - addLoader("MRUBYTE1", nullptr); + addLoader("LXMRU030"); + if (256 == n_mru) { + addLoader("MRUBYTE1"); + } else { + addLoader("MRUARB10"); } - else { - addLoader("MRUARB10", nullptr); - } - addLoader("LXMRU040", nullptr); + addLoader("LXMRU040"); } - addLoader("LXUNF030", nullptr); - if (NOFILT!=f_jcc2) { - addLoader("LXJCC000", nullptr); + addLoader("LXUNF030"); + if (NOFILT != f_jcc2) { + addLoader("LXJCC000"); } - if (NOFILT!=f_call || NOFILT!=f_jmp1) { // at least one is filtered + if (NOFILT != f_call || NOFILT != f_jmp1) { // at least one is filtered // shift opcode origin to zero - if (0==n_mru) { - addLoader("LXCJ0MRU", nullptr); - } - else { - addLoader("LXCJ1MRU", nullptr); + if (0 == n_mru) { + addLoader("LXCJ0MRU"); + } else { + addLoader("LXCJ1MRU"); } // determine if in range - if ((NOFILT!=f_call) && (NOFILT!=f_jmp1)) { // unfilter both - addLoader("LXCALJMP", nullptr); + if ((NOFILT != f_call) && (NOFILT != f_jmp1)) { // unfilter both + addLoader("LXCALJMP"); } - if ((NOFILT==f_call) ^ (NOFILT==f_jmp1)) { // unfilter just one - if (0==n_mru) { - addLoader("LXCALL00", nullptr); - } - else { - addLoader("LXCALL01", nullptr); + if ((NOFILT == f_call) ^ (NOFILT == f_jmp1)) { // unfilter just one + if (0 == n_mru) { + addLoader("LXCALL00"); + } else { + addLoader("LXCALL01"); } } // determine if mru applies - if (0==n_mru || ! ((FNOMRU==f_call) || (FNOMRU==f_jmp1)) ) { - addLoader("LXCJ2MRU", nullptr); // no mru, or no exceptions - } - else { // mru on one, but not the other - addLoader("LXCJ4MRU", nullptr); - if (MRUFLT==f_jmp1) { // JMP only - addLoader("LXCJ6MRU", nullptr); - } else - if (MRUFLT==f_call) { // CALL only - addLoader("LXCJ7MRU", nullptr); + if (0 == n_mru || !((FNOMRU == f_call) || (FNOMRU == f_jmp1))) { + // no mru, or no exceptions + addLoader("LXCJ2MRU"); + } else { + // mru on one, but not the other + addLoader("LXCJ4MRU"); + if (MRUFLT == f_jmp1) { // JMP only + addLoader("LXCJ6MRU"); + } else if (MRUFLT == f_call) { // CALL only + addLoader("LXCJ7MRU"); } - addLoader("LXCJ8MRU", nullptr); + addLoader("LXCJ8MRU"); } } - addLoader("LXUNF034", nullptr); + addLoader("LXUNF034"); if (n_mru) { - addLoader("LXMRU055", nullptr); - if (256==n_mru) { - addLoader("MRUBYTE2", nullptr); + addLoader("LXMRU055"); + if (256 == n_mru) { + addLoader("MRUBYTE2"); + } else if (mrupwr2) { + addLoader("MRUBITS2"); + } else if (n_mru) { + addLoader("MRUARB20"); } - else if (mrupwr2) { - addLoader("MRUBITS2", nullptr); - } - else if (n_mru) { - addLoader("MRUARB20", nullptr); - } - addLoader("LXMRU057", nullptr); + addLoader("LXMRU057"); } } } @@ -309,15 +267,12 @@ void Packer::addFilter32(int filter_id) #undef FNOMRU #undef MRUFLT - /************************************************************************* // **************************************************************************/ -void Packer::defineFilterSymbols(const Filter *ft) -{ - if (ft->id == 0) - { +void Packer::defineFilterSymbols(const Filter *ft) { + if (ft->id == 0) { linker->defineSymbol("filter_length", 0); linker->defineSymbol("filter_cto", 0); return; @@ -325,33 +280,26 @@ void Packer::defineFilterSymbols(const Filter *ft) assert(ft->calls > 0); assert(ft->buf_len > 0); - if (ft->id >= 0x40 && ft->id <= 0x4f) - { + if (ft->id >= 0x40 && ft->id <= 0x4f) { linker->defineSymbol("filter_length", ft->buf_len); linker->defineSymbol("filter_cto", ft->cto); - } - else if (ft->id >= 0x50 && ft->id <= 0x5f) - { + } else if (ft->id >= 0x50 && ft->id <= 0x5f) { linker->defineSymbol("filter_id", ft->id); linker->defineSymbol("filter_cto", ft->cto); - } - else if ((ft->id & 0xf) % 3 == 0) - { + } else if ((ft->id & 0xf) % 3 == 0) { linker->defineSymbol("filter_length", ft->calls); linker->defineSymbol("filter_cto", ft->cto); - } - else - { + } else { linker->defineSymbol("filter_length", ft->lastcall - ft->calls * 4); linker->defineSymbol("filter_cto", ft->cto); } #if 0 - if (0x80==(ft->id & 0xF0)) { - int const mru = ph.n_mru ? 1+ ph.n_mru : 0; - if (mru && mru!=256) { - unsigned const is_pwr2 = (0==((mru -1) & mru)); - //patch_le32(0x80 + (char *)loader, lsize - 0x80, "NMRU", mru - is_pwr2); + if (0x80 == (ft->id & 0xF0)) { + int const mru = ph.n_mru ? 1 + ph.n_mru : 0; + if (mru && mru != 256) { + unsigned const is_pwr2 = (0 == ((mru - 1) & mru)); + // patch_le32(0x80 + (char *) loader, lsize - 0x80, "NMRU", mru - is_pwr2); } } #endif diff --git a/src/pefile.cpp b/src/pefile.cpp index 2a2b59f9..d0b50cbf 100644 --- a/src/pefile.cpp +++ b/src/pefile.cpp @@ -33,52 +33,29 @@ #include "linker.h" #define FILLVAL 0 +#define import my_import // "import" is a keyword since C++20 /************************************************************************* // **************************************************************************/ -#if (WITH_XSPAN >= 2) && 1 -// #define IPTR(type, var) Span var(ibuf, ibuf.getSize(), ibuf) -// #define OPTR(type, var) Span var(obuf, obuf.getSize(), obuf) -#define IPTR_I_D(type, var, disp) \ - Span var(ibuf + (disp), ibuf.getSize() - (disp), ibuf + (disp)) -#define IPTR_I(type, var, first) Span var(first, ibuf) -#define OPTR_I(type, var, first) Span var(first, obuf) -#define IPTR_C(type, var, first) const Span var(first, ibuf) -#define OPTR_C(type, var, first) const Span var(first, obuf) -#else -#include "util/bptr.h" -// #define IPTR(type, var) BoundedPtr var(ibuf, ibuf.getSize()) -// #define OPTR(type, var) BoundedPtr var(obuf, obuf.getSize()) -#define IPTR_I_D(type, var, disp) \ - BoundedPtr var(ibuf + (disp), ibuf.getSize() - (disp), ibuf + (disp)) -#define IPTR_I(type, var, first) BoundedPtr var(ibuf, ibuf.getSize(), first) -#define OPTR_I(type, var, first) BoundedPtr var(obuf, obuf.getSize(), first) -#define IPTR_C(type, var, first) const BoundedPtr var(ibuf, ibuf.getSize(), first) -#define OPTR_C(type, var, first) const BoundedPtr var(obuf, obuf.getSize(), first) -#endif +#define IPTR_VAR(type, var, first) SPAN_S_VAR(type, var, first, ibuf) +#define OPTR_VAR(type, var, first) SPAN_S_VAR(type, var, first, obuf) +#define IPTR_VAR_OFFSET(type, var, offset) \ + SPAN_S_VAR(type, var, ibuf + (offset), ibuf.getSize() - (offset), ibuf + (offset)) static void xcheck(const void *p) { - if (!p) + if very_unlikely (p == nullptr) throwCantUnpack("xcheck unexpected nullptr pointer; take care!"); } static void xcheck(const void *p, size_t plen, const void *b, size_t blen) { const char *pp = (const char *) p; const char *bb = (const char *) b; - if (pp < bb || pp > bb + blen || pp + plen > bb + blen) + if very_unlikely (pp < bb || pp > bb + blen || pp + plen > bb + blen) throwCantUnpack("xcheck pointer out of range; take care!"); } -#if 0 -static void xcheck(size_t poff, size_t plen, const void *b, size_t blen) -{ - ACC_UNUSED(b); - if (poff > blen || poff + plen > blen) - throwCantUnpack("xcheck pointer out of range; take care!"); -} -#endif -#define ICHECK(x, size) xcheck(raw_bytes(x, 0), size, ibuf, ibuf.getSize()) -#define OCHECK(x, size) xcheck(raw_bytes(x, 0), size, obuf, obuf.getSize()) +#define ICHECK(p, bytes) xcheck(raw_bytes(p, 0), bytes, ibuf, ibuf.getSize()) +#define OCHECK(p, bytes) xcheck(raw_bytes(p, 0), bytes, obuf, obuf.getSize()) // #define imemset(a,b,c) ICHECK(a,c), memset(a,b,c) // #define omemset(a,b,c) OCHECK(a,c), memset(a,b,c) @@ -892,15 +869,15 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1 soimport += strlen(dlls[ic].name) + 1 + 4; - for (IPTR_I(LEXX, tarr, dlls[ic].lookupt); *tarr; tarr += 1) { + for (IPTR_VAR(const LEXX, tarr, dlls[ic].lookupt); *tarr; tarr += 1) { if (*tarr & ord_mask) { importbyordinal = true; soimport += 2; // ordinal num: 2 bytes dlls[ic].ordinal = *tarr & 0xffff; } else // it's an import by name { - IPTR_I(const upx_byte, n, ibuf + *tarr + 2); - unsigned len = strlen(n); + IPTR_VAR(const upx_byte, const name, ibuf + *tarr + 2); + unsigned len = strlen(name); soimport += len + 1; if (dlls[ic].shname == nullptr || len < strlen(dlls[ic].shname)) dlls[ic].shname = ibuf + *tarr + 2; @@ -1462,6 +1439,7 @@ PeFile::Resource::Resource(const upx_byte *p, const upx_byte *ibufstart_, const upx_byte *ibufend_) { ibufstart = ibufstart_; ibufend = ibufend_; + newstart = nullptr; init(p); } @@ -1945,7 +1923,7 @@ void PeFile::readSectionHeaders(unsigned objs, unsigned sizeof_ih) { if (objs == 0) return; mb_isection.alloc(mem_size(sizeof(pe_section_t), objs)); - isection = mb_isection; // => isection now is a SPAN_S + isection = SPAN_S_MAKE(pe_section_t, mb_isection); // => isection now is a SPAN_S if (file_size_u < pe_offset + sizeof_ih + sizeof(pe_section_t) * objs) { char buf[32]; snprintf(buf, sizeof(buf), "too many sections %d", objs); @@ -2599,7 +2577,7 @@ void PeFile::rebuildRelocs(SPAN_S(upx_byte) & extrainfo, unsigned bits, unsigned SPAN_S_VAR(upx_byte, const wrkmem, mb_wrkmem); for (unsigned ic = 0; ic < relocn; ic++) { - OPTR_I(upx_byte, p, obuf + get_le32(wrkmem + 4 * ic)); + OPTR_VAR(upx_byte, const p, obuf + get_le32(wrkmem + 4 * ic)); if (bits == 32) set_le32(p, get_le32(p) + imagebase + rvamin); else @@ -2648,8 +2626,8 @@ void PeFile::rebuildResources(SPAN_S(upx_byte) & extrainfo, unsigned lastvaddr) Resource res(r + vaddr, ibuf, ibuf + ibuf.getSize()); while (res.next()) if (res.offs() > vaddr) { - ICHECK(r + res.offs() - 4, 4); - unsigned origoffs = get_le32(r + res.offs() - 4); + ICHECK(r + (res.offs() - 4), 4); + unsigned origoffs = get_le32(r + (res.offs() - 4)); res.newoffs() = origoffs; omemcpy(obuf + (origoffs - rvamin), r + res.offs(), res.size()); if (icondir_count && res.itype() == RT_GROUP_ICON) { @@ -2671,14 +2649,14 @@ void PeFile::rebuildImports(SPAN_S(upx_byte) & extrainfo, ord_mask_t ord_mask, b if (ODADDR(PEDIR_IMPORT) == 0 || ODSIZE(PEDIR_IMPORT) <= sizeof(import_desc)) return; - OPTR_C(const upx_byte, idata, obuf + get_le32(extrainfo)); + OPTR_VAR(const upx_byte, const imdata, obuf + get_le32(extrainfo)); const unsigned inamespos = get_le32(extrainfo + 4); extrainfo += 8; unsigned sdllnames = 0; - IPTR_I_D(const upx_byte, import, IDADDR(PEDIR_IMPORT) - isection[2].vaddr); - OPTR_I(const upx_byte, p, raw_bytes(idata, 4)); + IPTR_VAR_OFFSET(const upx_byte, const import, IDADDR(PEDIR_IMPORT) - isection[2].vaddr); + OPTR_VAR(const upx_byte, p, raw_bytes(imdata, 4)); for (; get_le32(p) != 0; ++p) { const upx_byte *dname = raw_bytes(import + get_le32(p), 1); @@ -2688,7 +2666,7 @@ void PeFile::rebuildImports(SPAN_S(upx_byte) & extrainfo, ord_mask_t ord_mask, b sdllnames += dlen + 1; for (p += 8; *p;) if (*p == 1) - p += strlen(++p) + 1; + p += 1 + strlen(p + 1) + 1; else if (*p == 0xff) p += 3; // ordinal else @@ -2712,7 +2690,7 @@ void PeFile::rebuildImports(SPAN_S(upx_byte) & extrainfo, ord_mask_t ord_mask, b SPAN_0_VAR(upx_byte, const importednames_start, importednames); #endif - for (p = idata; get_le32(p) != 0; ++p) { + for (p = imdata; get_le32(p) != 0; ++p) { // restore the name of the dll const upx_byte *dname = raw_bytes(import + get_le32(p), 1); const unsigned dlen = strlen(dname); @@ -2722,7 +2700,7 @@ void PeFile::rebuildImports(SPAN_S(upx_byte) & extrainfo, ord_mask_t ord_mask, b if (inamespos) { // now I rebuild the dll names omemcpy(dllnames, dname, dlen + 1); - im->dllname = ptr_diff_bytes(dllnames, Obuf); + im->dllname = ptr_udiff_bytes(dllnames, Obuf); //;;;printf("\ndll: %s:",dllnames); dllnames += dlen + 1; } else { @@ -2732,18 +2710,18 @@ void PeFile::rebuildImports(SPAN_S(upx_byte) & extrainfo, ord_mask_t ord_mask, b if (set_oft) im->oft = iatoffs; - OPTR_I(LEXX, newiat, (LEXX *) (Obuf + iatoffs)); + OPTR_VAR(LEXX, newiat, (LEXX *) (Obuf + iatoffs)); // restore the imported names+ordinals for (p += 8; *p; ++newiat) if (*p == 1) { const unsigned ilen = strlen(++p) + 1; if (inamespos) { - if (ptr_diff_bytes(importednames, importednames_start) & 1) + if (ptr_udiff_bytes(importednames, importednames_start) & 1) importednames -= 1; omemcpy(importednames + 2, p, ilen); //;;;printf(" %s",importednames+2); - *newiat = ptr_diff_bytes(importednames, Obuf); + *newiat = ptr_udiff_bytes(importednames, Obuf); importednames += 2 + ilen; } else { // Beware overlap! @@ -2762,7 +2740,7 @@ void PeFile::rebuildImports(SPAN_S(upx_byte) & extrainfo, ord_mask_t ord_mask, b *newiat = 0; im++; } - // memset(idata,0,p - idata); + // memset(imdata, 0, ptr_udiff_bytes(p, imdata)); } template @@ -2864,16 +2842,16 @@ void PeFile::unpack0(OutputFile *fo, const ht &ih, ht &oh, ord_mask_t ord_mask, // write decompressed file if (fo) { - unsigned ic; - for (ic = 0; ic < objs && osection[ic].rawdataptr == 0; ic++) - ; + unsigned ic = 0; + while (ic < objs && osection[ic].rawdataptr == 0) + ic++; ibuf.dealloc(); ibuf.alloc(osection[ic].rawdataptr); ibuf.clear(); infoHeader("[Writing uncompressed file]"); - // write loader + compressed file + // write header + decompressed file fo->write(&oh, sizeof(oh)); fo->write(osection, objs * sizeof(pe_section_t)); fo->write(ibuf, osection[ic].rawdataptr - fo->getBytesWritten()); @@ -2891,7 +2869,7 @@ int PeFile::canUnpack0(unsigned max_sections, unsigned objs, unsigned ih_entry, if (objs < min_sections) return -1; mb_isection.alloc(mem_size(sizeof(pe_section_t), objs)); - isection = mb_isection; // => isection now is a SPAN_S + isection = SPAN_S_MAKE(pe_section_t, mb_isection); // => isection now is a SPAN_S fi->seek(pe_offset + ih_size, SEEK_SET); fi->readx(isection, sizeof(pe_section_t) * objs); bool is_packed = (objs <= max_sections && (IDSIZE(15) || ih_entry > isection[1].vaddr)); diff --git a/src/ui.cpp b/src/ui.cpp index f74ef9fc..7e443b18 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -25,6 +25,9 @@ */ +// INFO: not thread-safe; assumes a single UiPacker instance that +// is exclusively called from main thread + #include "conf.h" #include "file.h" #include "packer.h" @@ -92,19 +95,14 @@ unsigned UiPacker::update_fu_len = 0; **************************************************************************/ static const char header_line1[] = " File size Ratio Format Name\n"; -static char header_line2[] = " -------------------- ------ ----------- -----------\n"; +static const char header_line2[] = " -------------------- ------ ----------- -----------\n"; -static char progress_filler[4 + 1] = ".*[]"; +static const char progress_filler[4 + 1] = ".*[]"; -static void init_global_constants(void) { +static void init_global_constants(void) noexcept { #if 0 && (ACC_OS_DOS16 || ACC_OS_DOS32) // FIXME: should test codepage here - static bool done = false; - if (done) - return; - done = true; - #if 1 && (ACC_OS_DOS32) && defined(__DJGPP__) /* check for Windows NT/2000/XP */ if (_get_dos_version(1) == 0x0532) @@ -158,7 +156,8 @@ static const char *mkline(upx_uint64_t fu_len, upx_uint64_t fc_len, upx_uint64_t **************************************************************************/ UiPacker::UiPacker(const Packer *p_) : ui_pass(0), ui_total_passes(0), p(p_), s(nullptr) { - init_global_constants(); + static upx_std_once_flag init_done; + upx_std_call_once(init_done, init_global_constants); cb.reset(); diff --git a/src/util/bptr.h b/src/util/bptr.h deleted file mode 100644 index 3fe4a334..00000000 --- a/src/util/bptr.h +++ /dev/null @@ -1,155 +0,0 @@ -/* bptr.h -- - - This file is part of the UPX executable compressor. - - Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer - Copyright (C) 1996-2023 Laszlo Molnar - 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 Laszlo Molnar - - */ - -#pragma once -#ifndef UPX_BPTR_H__ -#define UPX_BPTR_H__ 1 - -#if WITH_XSPAN >= 2 -#error "this file is deprecated, please use xspan.h instead" -#endif - -/************************************************************************* -// BoundedPtr -**************************************************************************/ - -template -class BoundedPtr { -public: - typedef T element_type; - typedef typename std::add_pointer::type pointer; - - ~BoundedPtr() {} - - BoundedPtr(void *base, size_t size_in_bytes, T *ptr = nullptr) - : ptr_(ptr), base_(base), size_in_bytes_(0) { - assert(base_ != nullptr); - size_in_bytes_ = mem_size(1, size_in_bytes); - check(); - } - - // assignment - BoundedPtr &operator=(const BoundedPtr &other) { - assert(base_ == other.base_); - assert(size_in_bytes_ == other.size_in_bytes_); - ptr_ = other.ptr_; - check(); - return *this; - } - BoundedPtr &operator=(T *other) { - ptr_ = other; - check(); - return *this; - } - - // dereference - T &operator*() { - checkNULL(); - checkRange(ptr_ + 1); - return *ptr_; - } - const T &operator*() const { - checkNULL(); - checkRange(ptr_ + 1); - return *ptr_; - } - - operator T *() { return ptr_; } - operator const T *() const { return ptr_; } - - BoundedPtr &operator+=(size_t n) { - checkNULL(); - ptr_ += n; - checkRange(); - return *this; - } - BoundedPtr &operator-=(size_t n) { - checkNULL(); - ptr_ -= n; - checkRange(); - return *this; - } - BoundedPtr &operator++(void) { - checkNULL(); - ptr_ += 1; - checkRange(); - return *this; - } - - T *raw_bytes(size_t bytes) const { - checkNULL(); - if (bytes > 0) - checkRange((const char *) (const void *) ptr_ + bytes); - return ptr_; - } - -private: - void checkNULL() const { - if very_unlikely (!ptr_) - throwCantUnpack("unexpected NULL pointer; take care!"); - } - forceinline void checkRange() const { checkRange(ptr_, base_, size_in_bytes_); } - forceinline void checkRange(const void *p) const { checkRange(p, base_, size_in_bytes_); } - static void checkRange(const void *ptr, const void *base, size_t size_in_bytes) { - size_t off = (const char *) ptr - (const char *) base; - if very_unlikely (off > size_in_bytes) - throwCantUnpack("pointer out of range; take care!"); - } - void check() const { // check ptr_ invariant: either NULL or valid checkRange() - if (ptr_ != nullptr) - checkRange(); - } - - T *ptr_; - void *base_; - size_t size_in_bytes_; - - // disable copy - BoundedPtr(const BoundedPtr &) = delete; - // disable dynamic allocation - ACC_CXX_DISABLE_NEW_DELETE - - // disable taking the address => force passing by reference - // [I'm not too sure about this design decision, but we can always allow it if needed] - BoundedPtr *operator&() const = delete; -}; - -// raw_bytes overload -template -inline typename BoundedPtr::pointer raw_bytes(const BoundedPtr &a, size_t size_in_bytes) { - return a.raw_bytes(size_in_bytes); -} -template -inline typename BoundedPtr::pointer raw_index_bytes(const BoundedPtr &a, size_t index, - size_t size_in_bytes) { - typedef typename BoundedPtr::element_type element_type; - return raw_bytes(a, mem_size(sizeof(element_type), index, size_in_bytes)) + index; -} - -#endif /* already included */ - -/* vim:set ts=4 sw=4 et: */ diff --git a/src/util/membuffer.cpp b/src/util/membuffer.cpp index 5a94f5bc..9886aef5 100644 --- a/src/util/membuffer.cpp +++ b/src/util/membuffer.cpp @@ -47,18 +47,19 @@ unsigned membuffer_get_size(MemBuffer &mb) { return mb.getSize(); } #if defined(__SANITIZE_ADDRESS__) static forceinline constexpr bool use_simple_mcheck() { return false; } #elif (WITH_VALGRIND) && defined(RUNNING_ON_VALGRIND) -static int use_simple_mcheck_flag = -1; -static noinline void use_simple_mcheck_init() { - use_simple_mcheck_flag = 1; +static bool use_simple_mcheck_flag; +static noinline void init_use_simple_mcheck() noexcept { + bool r = true; if (RUNNING_ON_VALGRIND) { - use_simple_mcheck_flag = 0; - // fprintf(stderr, "upx: detected RUNNING_ON_VALGRIND\n"); + r = false; + NO_fprintf(stderr, "upx: detected RUNNING_ON_VALGRIND\n"); } + use_simple_mcheck_flag = r; } -static forceinline bool use_simple_mcheck() { - if very_unlikely (use_simple_mcheck_flag < 0) - use_simple_mcheck_init(); - return (bool) use_simple_mcheck_flag; +static bool use_simple_mcheck() { + static upx_std_once_flag init_done; + upx_std_call_once(init_done, init_use_simple_mcheck); + return use_simple_mcheck_flag; } #else static forceinline constexpr bool use_simple_mcheck() { return true; } @@ -68,8 +69,8 @@ static forceinline constexpr bool use_simple_mcheck() { return true; } // **************************************************************************/ -MemBuffer::MemBuffer(upx_uint64_t size_in_bytes) { - alloc(size_in_bytes); +MemBuffer::MemBuffer(upx_uint64_t bytes) { + alloc(bytes); debug_set(debug.last_return_address_alloc, upx_return_address()); } @@ -80,7 +81,7 @@ MemBuffer::~MemBuffer() { this->dealloc(); } void *MemBuffer::subref_impl(const char *errfmt, size_t skip, size_t take) { debug_set(debug.last_return_address_subref, upx_return_address()); // check overrun and wrap-around - if (skip + take > b_size_in_bytes || skip + take < skip) { + if (skip + take > size_in_bytes || skip + take < skip) { char buf[100]; // printf is using unsigned formatting if (!errfmt || !errfmt[0]) @@ -88,7 +89,7 @@ void *MemBuffer::subref_impl(const char *errfmt, size_t skip, size_t take) { snprintf(buf, sizeof(buf), errfmt, (unsigned) skip, (unsigned) take); throwCantPack(buf); } - return &b[skip]; + return ptr + skip; } static unsigned width(unsigned x) { @@ -116,62 +117,55 @@ static unsigned width(unsigned x) { return 1 + w; } -static inline unsigned umax(unsigned a, unsigned b) { return (a >= b) ? a : b; } +static forceinline size_t umax(size_t a, size_t b) { return (a >= b) ? a : b; } unsigned MemBuffer::getSizeForCompression(unsigned uncompressed_size, unsigned extra) { if (uncompressed_size == 0) throwCantPack("invalid uncompressed_size"); - const unsigned z = uncompressed_size; // fewer keystrokes and display columns - const unsigned w = umax(8, width(z - 1)); // ignore tiny offsets - unsigned bytes = ACC_ICONV(unsigned, mem_size(1, z)); // check + const size_t z = uncompressed_size; // fewer keystrokes and display columns + const size_t w = umax(8, width(z - 1)); // ignore tiny offsets + size_t bytes = mem_size(1, z); // check size // Worst matching: All match at max_offset, which implies 3==min_match - // All literal: 1 bit overhead per literal byte - bytes = umax(bytes, z + z / 8); + // All literal: 1 bit overhead per literal byte; from UCL documentation + bytes = umax(bytes, z + z / 8 + 256); // NRV2B: 1 byte plus 2 bits per width exceeding 8 ("ss11") bytes = umax(bytes, (z / 3 * (8 + 2 * (w - 8) / 1)) / 8); // NRV2E: 1 byte plus 3 bits per pair of width exceeding 7 ("ss12") bytes = umax(bytes, (z / 3 * (8 + 3 * (w - 7) / 2)) / 8); // zstd: ZSTD_COMPRESSBOUND bytes = umax(bytes, z + (z >> 8) + ((z < (128 << 10)) ? (((128 << 10) - z) >> 11) : 0)); - // extra + 256 safety for rounding + // add extra and 256 safety for various rounding/alignments bytes = mem_size(1, bytes, extra, 256); UNUSED(w); - return bytes; + return ACC_ICONV(unsigned, bytes); } unsigned MemBuffer::getSizeForDecompression(unsigned uncompressed_size, unsigned extra) { if (uncompressed_size == 0) throwCantPack("invalid uncompressed_size"); - size_t bytes = mem_size(1, uncompressed_size, extra); // check + size_t bytes = mem_size(1, uncompressed_size, extra); // check size return ACC_ICONV(unsigned, bytes); } void MemBuffer::allocForCompression(unsigned uncompressed_size, unsigned extra) { - if (uncompressed_size == 0) - throwCantPack("invalid uncompressed_size"); - unsigned size = getSizeForCompression(uncompressed_size, extra); - alloc(size); + unsigned bytes = getSizeForCompression(uncompressed_size, extra); + alloc(bytes); debug_set(debug.last_return_address_alloc, upx_return_address()); } void MemBuffer::allocForDecompression(unsigned uncompressed_size, unsigned extra) { - if (uncompressed_size == 0) - throwCantPack("invalid uncompressed_size"); - unsigned size = getSizeForDecompression(uncompressed_size, extra); - alloc(size); + unsigned bytes = getSizeForDecompression(uncompressed_size, extra); + alloc(bytes); debug_set(debug.last_return_address_alloc, upx_return_address()); } void MemBuffer::fill(unsigned off, unsigned len, int value) { debug_set(debug.last_return_address_fill, upx_return_address()); checkState(); - assert((int) off >= 0); - assert((int) len >= 0); - assert(off <= b_size_in_bytes); - assert(len <= b_size_in_bytes); - assert(off + len <= b_size_in_bytes); + if (off > size_in_bytes || len > size_in_bytes || off + len > size_in_bytes) + throwCantPack("MemBuffer::fill out of range; take care!"); if (len > 0) - memset(b + off, value, len); + memset(ptr + off, value, len); } /************************************************************************* @@ -183,22 +177,22 @@ void MemBuffer::fill(unsigned off, unsigned len, int value) { #define MAGIC2(p) ((PTR_BITS(p) ^ 0xfefdbeeb ^ 0x80024011) | 1) void MemBuffer::checkState() const { - if (!b) + if (!ptr) throwInternalError("block not allocated"); if (use_simple_mcheck()) { - if (get_ne32(b - 4) != MAGIC1(b)) + if (get_ne32(ptr - 4) != MAGIC1(ptr)) throwInternalError("memory clobbered before allocated block 1"); - if (get_ne32(b - 8) != b_size_in_bytes) + if (get_ne32(ptr - 8) != size_in_bytes) throwInternalError("memory clobbered before allocated block 2"); - if (get_ne32(b + b_size_in_bytes) != MAGIC2(b)) + if (get_ne32(ptr + size_in_bytes) != MAGIC2(ptr)) throwInternalError("memory clobbered past end of allocated block"); } } void MemBuffer::alloc(upx_uint64_t size) { // NOTE: we don't automatically free a used buffer - assert(b == nullptr); - assert(b_size_in_bytes == 0); + assert(ptr == nullptr); + assert(size_in_bytes == 0); // assert(size > 0); debug_set(debug.last_return_address_alloc, upx_return_address()); @@ -207,44 +201,44 @@ void MemBuffer::alloc(upx_uint64_t size) { NO_printf("MemBuffer::alloc %llu: %p\n", size, p); if (!p) throwOutOfMemoryException(); - b = p; - b_size_in_bytes = ACC_ICONV(unsigned, size); + ptr = p; + size_in_bytes = ACC_ICONV(unsigned, size); if (use_simple_mcheck()) { - b = p + 16; + ptr = p + 16; // store magic constants to detect buffer overruns - set_ne32(b - 8, b_size_in_bytes); - set_ne32(b - 4, MAGIC1(b)); - set_ne32(b + b_size_in_bytes, MAGIC2(b)); - set_ne32(b + b_size_in_bytes + 4, stats.global_alloc_counter); + set_ne32(ptr - 8, size_in_bytes); + set_ne32(ptr - 4, MAGIC1(ptr)); + set_ne32(ptr + size_in_bytes, MAGIC2(ptr)); + set_ne32(ptr + size_in_bytes + 4, stats.global_alloc_counter); } #if !defined(__SANITIZE_ADDRESS__) && 0 - fill(0, b_size_in_bytes, (rand() & 0xff) | 1); // debug - (void) VALGRIND_MAKE_MEM_UNDEFINED(b, b_size_in_bytes); + fill(0, size_in_bytes, (rand() & 0xff) | 1); // debug + (void) VALGRIND_MAKE_MEM_UNDEFINED(ptr, size_in_bytes); #endif stats.global_alloc_counter += 1; - stats.global_total_bytes += b_size_in_bytes; - stats.global_total_active_bytes += b_size_in_bytes; + stats.global_total_bytes += size_in_bytes; + stats.global_total_active_bytes += size_in_bytes; } void MemBuffer::dealloc() { - if (b != nullptr) { + if (ptr != nullptr) { debug_set(debug.last_return_address_dealloc, upx_return_address()); checkState(); - stats.global_total_active_bytes -= b_size_in_bytes; + stats.global_total_active_bytes -= size_in_bytes; if (use_simple_mcheck()) { // clear magic constants - set_ne32(b - 8, 0); - set_ne32(b - 4, 0); - set_ne32(b + b_size_in_bytes, 0); - set_ne32(b + b_size_in_bytes + 4, 0); + set_ne32(ptr - 8, 0); + set_ne32(ptr - 4, 0); + set_ne32(ptr + size_in_bytes, 0); + set_ne32(ptr + size_in_bytes + 4, 0); // - ::free(b - 16); + ::free(ptr - 16); } else - ::free(b); - b = nullptr; - b_size_in_bytes = 0; + ::free(ptr); + ptr = nullptr; + size_in_bytes = 0; } else { - assert(b_size_in_bytes == 0); + assert(size_in_bytes == 0); } } @@ -264,9 +258,11 @@ TEST_CASE("MemBuffer") { CHECK(raw_bytes(mb, 64) == mb.getVoidPtr()); CHECK_THROWS(raw_bytes(mb, 65)); CHECK_NOTHROW(mb + 64); - CHECK_NOTHROW(64 + mb); CHECK_THROWS(mb + 65); +#if ALLOW_INT_PLUS_MEMBUFFER + CHECK_NOTHROW(64 + mb); CHECK_THROWS(65 + mb); +#endif if (use_simple_mcheck()) { upx_byte *b = raw_bytes(mb, 0); unsigned magic1 = get_ne32(b - 4); @@ -280,9 +276,9 @@ TEST_CASE("MemBuffer") { TEST_CASE("MemBuffer::getSizeForCompression") { CHECK_THROWS(MemBuffer::getSizeForCompression(0)); CHECK_THROWS(MemBuffer::getSizeForDecompression(0)); - CHECK(MemBuffer::getSizeForCompression(1) == 320); - CHECK(MemBuffer::getSizeForCompression(256) == 576); - CHECK(MemBuffer::getSizeForCompression(1024) == 1408); + CHECK(MemBuffer::getSizeForCompression(1) == 513); + CHECK(MemBuffer::getSizeForCompression(256) == 800); + CHECK(MemBuffer::getSizeForCompression(1024) == 1664); // CHECK(MemBuffer::getSizeForCompression(1024 * 1024) == 0); // TODO // CHECK(MemBuffer::getSizeForCompression(UPX_RSIZE_MAX) == 0); // TODO } diff --git a/src/util/membuffer.h b/src/util/membuffer.h index 65f1b678..86ef5683 100644 --- a/src/util/membuffer.h +++ b/src/util/membuffer.h @@ -37,18 +37,20 @@ template class MemBufferBase { public: typedef T element_type; + typedef typename std::add_lvalue_reference::type reference; typedef typename std::add_pointer::type pointer; + typedef unsigned size_type; protected: - pointer b; - unsigned b_size_in_bytes; + pointer ptr; + size_type size_in_bytes; public: - MemBufferBase() : b(nullptr), b_size_in_bytes(0) {} + MemBufferBase() : ptr(nullptr), size_in_bytes(0) {} // NOTE: implicit conversion to underlying pointer // NOTE: for fully bound-checked pointer use XSPAN_S from xspan.h - operator pointer() const { return b; } + operator pointer() const { return ptr; } template typename std::enable_if::value, pointer>::type operator+(U n) const { @@ -59,18 +61,21 @@ public: private: // NOT allowed; use raw_bytes() instead template - typename std::enable_if::value, pointer>::type - operator-(U n) const DELETED_FUNCTION; + typename std::enable_if::value, pointer>::type operator-(U n) const + DELETED_FUNCTION; + +public: // raw access + pointer raw_ptr() const { return ptr; } + size_type raw_size_in_bytes() const { return size_in_bytes; } -public: pointer raw_bytes(size_t bytes) const { if (bytes > 0) { - if very_unlikely (b == nullptr) - throwInternalError("MemBuffer raw_bytes unexpected NULL ptr"); - if very_unlikely (bytes > b_size_in_bytes) - throwInternalError("MemBuffer raw_bytes invalid size"); + if very_unlikely (ptr == nullptr) + throwCantPack("MemBuffer raw_bytes unexpected NULL ptr"); + if very_unlikely (bytes > size_in_bytes) + throwCantPack("MemBuffer raw_bytes invalid size"); } - return b; + return ptr; } }; @@ -89,19 +94,19 @@ public: void dealloc(); void checkState() const; - unsigned getSize() const { return b_size_in_bytes; } + unsigned getSize() const { return size_in_bytes; } // explicit converstion - void *getVoidPtr() { return (void *) b; } - const void *getVoidPtr() const { return (const void *) b; } + void *getVoidPtr() { return (void *) ptr; } + const void *getVoidPtr() const { return (const void *) ptr; } // util void fill(unsigned off, unsigned len, int value); forceinline void clear(unsigned off, unsigned len) { fill(off, len, 0); } - forceinline void clear() { fill(0, b_size_in_bytes, 0); } + forceinline void clear() { fill(0, size_in_bytes, 0); } // If the entire range [skip, skip+take) is inside the buffer, - // then return &b[skip]; else throwCantPack(sprintf(errfmt, skip, take)). + // then return &ptr[skip]; else throwCantPack(sprintf(errfmt, skip, take)). // This is similar to BoundedPtr, except only checks once. // skip == offset, take == size_in_bytes forceinline pointer subref(const char *errfmt, size_t skip, size_t take) { @@ -130,7 +135,7 @@ private: Debug debug; #endif - // disable copy, assignment and move + // disable copy and move MemBuffer(const MemBuffer &) DELETED_FUNCTION; MemBuffer &operator=(const MemBuffer &) DELETED_FUNCTION; #if __cplusplus >= 201103L @@ -159,11 +164,17 @@ inline typename MemBufferBase::pointer raw_index_bytes(const MemBufferBase } // global operators +#if ALLOW_INT_PLUS_MEMBUFFER // rewrite "n + membuffer" to "membuffer + n" so that this will get checked above template inline typename std::enable_if::value, typename MemBufferBase::pointer>::type operator+(U n, const MemBufferBase &mbb) { return mbb + n; } +#else +template +inline typename std::enable_if::value, typename MemBufferBase::pointer>::type +operator+(U n, const MemBufferBase &mbb) DELETED_FUNCTION; +#endif /* vim:set ts=4 sw=4 et: */ diff --git a/src/util/util.cpp b/src/util/util.cpp index c9eb4a5f..df7d1205 100644 --- a/src/util/util.cpp +++ b/src/util/util.cpp @@ -47,7 +47,9 @@ ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_MEM == UPX_RSIZE_MAX) ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_STR <= UPX_RSIZE_MAX / 256) ACC_COMPILE_TIME_ASSERT_HEADER(2ull * UPX_RSIZE_MAX * 9 / 8 + 16 * 1024 * 1024 < INT_MAX) -ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX >= 65536 * 8192) +ACC_COMPILE_TIME_ASSERT_HEADER(5ull * UPX_RSIZE_MAX < UINT_MAX) +ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX >= 8192 * 65536) +ACC_COMPILE_TIME_ASSERT_HEADER(UPX_RSIZE_MAX_STR >= 1024) upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1, upx_uint64_t extra2) { diff --git a/src/util/xspan.h b/src/util/xspan.h index 897dc5bf..6cfef65b 100644 --- a/src/util/xspan.h +++ b/src/util/xspan.h @@ -161,8 +161,7 @@ inline R *xspan_make_helper__(R * /*dummy*/, MemBuffer &first) { /************************************************************************* // raw_bytes() - get underlying memory from checked buffers/pointers. -// This is overloaded by various utility classes like BoundedPtr, -// MemBuffer and XSpan. +// This is overloaded by various utility classes like MemBuffer and XSpan. // // Note that the pointer type is retained, the "_bytes" hints size_in_bytes **************************************************************************/ diff --git a/src/util/xspan_fwd.h b/src/util/xspan_fwd.h index 4b4f3055..b28f4d06 100644 --- a/src/util/xspan_fwd.h +++ b/src/util/xspan_fwd.h @@ -31,6 +31,10 @@ template \ inline XSPAN_REQUIRES_CONVERTIBLE_ANY_DIRECTION(T, U, RType) +template +inline typename std::enable_if::value, void *>::type operator+(U, const C &) + DELETED_FUNCTION; + /************************************************************************* // overloads for standard functions **************************************************************************/ diff --git a/src/version.h b/src/version.h index 18822cbd..ac347f86 100644 --- a/src/version.h +++ b/src/version.h @@ -1,8 +1,8 @@ #define UPX_VERSION_HEX 0x040003 /* 04.00.03 */ #define UPX_VERSION_STRING "4.0.3" #define UPX_VERSION_STRING4 "4.03" -#define UPX_VERSION_DATE "Jan 30th 2023" -#define UPX_VERSION_DATE_ISO "2023-01-30" +#define UPX_VERSION_DATE "Feb 5th 2023" +#define UPX_VERSION_DATE_ISO "2023-02-05" #define UPX_VERSION_YEAR "2023" /* vim:set ts=4 sw=4 et: */ diff --git a/src/work.cpp b/src/work.cpp index 9348af0d..88849e7c 100644 --- a/src/work.cpp +++ b/src/work.cpp @@ -25,9 +25,10 @@ */ -// work.cpp implements the central loop, and it uses class PackMaster to +// This file implements the central loop, and it uses class PackMaster to // dispatch. PackMaster by itself will instatiate a concrete subclass // of class Packer which then does the actual work. +// And see p_com.cpp for a simple executable format. #include "conf.h" #include "file.h" @@ -155,7 +156,7 @@ void do_one_file(const char *iname, char *oname) { } } - // handle command + // handle command - actual work is here PackMaster pm(&fi, opt); if (opt->cmd == CMD_COMPRESS) pm.pack(&fo); @@ -258,7 +259,7 @@ static void unlink_ofile(char *oname) { IGNORE_ERROR(r); #endif if (unlink(oname) == 0) - oname[0] = 0; + oname[0] = 0; // done with oname } }