all: assorted cleanups and updates
Changes include: - add a bunch of "noexcept", mostly to operators and forceinline - use "uchar" - use "charptr" - rename options_t to Options - add ptr_check_no_overlap() - rewrite p_exe.cpp, NFCI - clang-format help.cpp - spelling fixes
This commit is contained in:
parent
127fd095e7
commit
a627648249
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -377,8 +377,8 @@ jobs:
|
||||
- { zig_target: x86_64-macos.13-none }
|
||||
- { zig_target: x86_64-windows-gnu }
|
||||
env:
|
||||
# 2023-02-19
|
||||
ZIG_DIST_VERSION: 0.11.0-dev.1650+5e7b09ce9
|
||||
# 2023-03-14
|
||||
ZIG_DIST_VERSION: 0.11.0-dev.1970+962299157
|
||||
# for zig-cc wrapper scripts (see below):
|
||||
ZIG_CPPFLAGS: -DUPX_DOCTEST_CONFIG_MULTITHREADING
|
||||
ZIG_FLAGS: ${{ matrix.zig_flags }}
|
||||
|
||||
2
.github/workflows/close-stale-issues.yml
vendored
2
.github/workflows/close-stale-issues.yml
vendored
@ -27,7 +27,7 @@ jobs:
|
||||
with:
|
||||
operations-per-run: 300
|
||||
exempt-all-milestones: true
|
||||
exempt-issue-labels: 'blocker,enhancement,regression'
|
||||
exempt-issue-labels: 'blocker,enhancement,help wanted,regression'
|
||||
days-before-stale: 60
|
||||
days-before-close: 30
|
||||
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Please remove the stale label or add a comment or this issue will be closed in 30 days.'
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR)
|
||||
cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR) # CMake >= 3.20.0 is recommended
|
||||
|
||||
# compilation config options
|
||||
if(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git")
|
||||
@ -101,9 +101,13 @@ endif()
|
||||
# targets
|
||||
#***********************************************************************
|
||||
|
||||
#find_package(Threads) # multithreading is currently not used; maybe in UPX version 5
|
||||
set(UPX_CONFIG_DISABLE_THREADS ON) # multithreading is currently not used; maybe in UPX version 5
|
||||
set(UPX_CONFIG_DISABLE_ZSTD ON) # zstd is currently not used; maybe in UPX version 5
|
||||
|
||||
if(NOT UPX_CONFIG_DISABLE_THREADS)
|
||||
find_package(Threads)
|
||||
endif()
|
||||
|
||||
file(GLOB ucl_SOURCES "vendor/ucl/src/*.c")
|
||||
list(SORT ucl_SOURCES)
|
||||
add_library(upx_vendor_ucl STATIC ${ucl_SOURCES})
|
||||
@ -129,6 +133,9 @@ target_link_libraries(upx upx_vendor_ucl upx_vendor_zlib)
|
||||
if(NOT UPX_CONFIG_DISABLE_ZSTD)
|
||||
target_link_libraries(upx upx_vendor_zstd)
|
||||
endif()
|
||||
if(Threads_FOUND)
|
||||
target_link_libraries(upx Threads::Threads)
|
||||
endif()
|
||||
|
||||
#***********************************************************************
|
||||
# compilation flags
|
||||
@ -215,10 +222,11 @@ endif()
|
||||
set(t upx_vendor_zlib)
|
||||
upx_compile_target_debug_with_O2(${t})
|
||||
upx_sanitize_target(${t})
|
||||
target_compile_definitions(${t} PRIVATE HAVE_STDARG_H=1 HAVE_VSNPRINTF=1)
|
||||
if(MSVC)
|
||||
target_compile_options(${t} PRIVATE -DHAVE_STDARG_H -DHAVE_VSNPRINTF -J -W3 ${warn_WX})
|
||||
target_compile_options(${t} PRIVATE -J -W3 ${warn_WX})
|
||||
else()
|
||||
target_compile_options(${t} PRIVATE -DHAVE_STDARG_H -DHAVE_UNISTD_H -DHAVE_VSNPRINTF)
|
||||
target_compile_definitions(${t} PRIVATE HAVE_UNISTD_H=1)
|
||||
# clang-15: -Wno-strict-prototypes is needed to silence the new -Wdeprecated-non-prototype warning
|
||||
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})
|
||||
@ -228,7 +236,7 @@ if(NOT UPX_CONFIG_DISABLE_ZSTD)
|
||||
set(t upx_vendor_zstd)
|
||||
upx_compile_target_debug_with_O2(${t})
|
||||
upx_sanitize_target(${t})
|
||||
target_compile_options(${t} PRIVATE -DDYNAMIC_BMI2=0 -DZSTD_DISABLE_ASM)
|
||||
target_compile_definitions(${t} PRIVATE DYNAMIC_BMI2=0 ZSTD_DISABLE_ASM=1)
|
||||
if(MSVC)
|
||||
target_compile_options(${t} PRIVATE -J ${warn_WN} ${warn_WX})
|
||||
else()
|
||||
@ -245,6 +253,9 @@ if(GITREV_SHORT)
|
||||
target_compile_definitions(${t} PRIVATE UPX_VERSION_GIT_DESCRIBE="${GIT_DESCRIBE}")
|
||||
endif()
|
||||
endif()
|
||||
if(Threads_FOUND)
|
||||
target_compile_definitions(${t} PRIVATE WITH_THREADS=1)
|
||||
endif()
|
||||
if(UPX_CONFIG_DISABLE_WSTRICT)
|
||||
target_compile_definitions(${t} PRIVATE UPX_CONFIG_DISABLE_WSTRICT=1)
|
||||
endif()
|
||||
@ -263,9 +274,9 @@ else()
|
||||
endif()
|
||||
|
||||
#***********************************************************************
|
||||
# "ctest"
|
||||
# "make test"
|
||||
# "ninja test"
|
||||
# ctest
|
||||
# make test
|
||||
# ninja test
|
||||
#***********************************************************************
|
||||
|
||||
if(NOT UPX_CONFIG_CMAKE_DISABLE_TEST)
|
||||
@ -302,9 +313,9 @@ endif()
|
||||
endif() # UPX_CONFIG_CMAKE_DISABLE_TEST
|
||||
|
||||
#***********************************************************************
|
||||
# "cmake --install ."
|
||||
# "make install"
|
||||
# "ninja install"
|
||||
# cmake --install .
|
||||
# make install
|
||||
# ninja install
|
||||
#***********************************************************************
|
||||
|
||||
if(NOT UPX_CONFIG_CMAKE_DISABLE_INSTALL)
|
||||
@ -350,12 +361,12 @@ 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|None|Release)$")
|
||||
message(WARNING "WARNING: unsupported CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}; please use \"Debug\" or \"Release\"")
|
||||
endif()
|
||||
|
||||
if(NOT UPX_CONFIG_CMAKE_DISABLE_PLATFORM_CHECK)
|
||||
# extra sanity checks to detect incompatible C vs CXX settings
|
||||
if(NOT UPX_CONFIG_CMAKE_DISABLE_PLATFORM_CHECK)
|
||||
if(NOT ",${CMAKE_C_PLATFORM_ID}," STREQUAL ",${CMAKE_CXX_PLATFORM_ID},")
|
||||
message(FATAL_ERROR "ERROR: CMAKE_C_PLATFORM_ID CMAKE_CXX_PLATFORM_ID mismatch")
|
||||
endif()
|
||||
|
||||
11
Makefile
11
Makefile
@ -44,8 +44,9 @@ all: build/debug build/release
|
||||
debug: build/debug
|
||||
release: build/release
|
||||
|
||||
.PHONY: PHONY
|
||||
.NOTPARALLEL: # because the actual builds use "cmake --parallel"
|
||||
.PHONY: PHONY
|
||||
.SECONDEXPANSION:
|
||||
.SUFFIXES:
|
||||
|
||||
# END of Makefile; extra stuff follows
|
||||
@ -114,7 +115,7 @@ build/extra/scan-build/%: CMAKE := scan-build $(CMAKE)
|
||||
build/extra/scan-build/%: export CCC_CC ?= clang
|
||||
build/extra/scan-build/%: export CCC_CXX ?= clang++
|
||||
|
||||
# cross compiler: Linux glibc aarch64-linux-gnu
|
||||
# cross compiler: Linux glibc aarch64-linux-gnu (arm64)
|
||||
build/extra/cross-linux-aarch64/debug: PHONY; $(call run_config_and_build,$@,Debug)
|
||||
build/extra/cross-linux-aarch64/release: PHONY; $(call run_config_and_build,$@,Release)
|
||||
build/extra/cross-linux-aarch64/%: export CC = aarch64-linux-gnu-gcc
|
||||
@ -126,13 +127,13 @@ build/extra/cross-linux-arm/release: PHONY; $(call run_config_and_build,$@,Relea
|
||||
build/extra/cross-linux-arm/%: export CC = arm-linux-gnueabihf-gcc
|
||||
build/extra/cross-linux-arm/%: export CXX = arm-linux-gnueabihf-g++ -Wno-psabi
|
||||
|
||||
# cross compiler: Windows x86 win32 MinGW
|
||||
# cross compiler: Windows x86 win32 MinGW (i386)
|
||||
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 -static
|
||||
build/extra/cross-windows-mingw32/%: export CXX = i686-w64-mingw32-g++ -static
|
||||
|
||||
# cross compiler: Windows x64 win64 MinGW
|
||||
# cross compiler: Windows x64 win64 MinGW (amd64)
|
||||
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 -static
|
||||
@ -144,7 +145,7 @@ build/extra/cross-darwin-arm64/release: PHONY; $(call run_config_and_build,$@,Re
|
||||
build/extra/cross-darwin-arm64/%: export CC = clang -target arm64-apple-darwin
|
||||
build/extra/cross-darwin-arm64/%: export CXX = clang++ -target arm64-apple-darwin
|
||||
|
||||
# cross compiler: macOS x86_64
|
||||
# cross compiler: macOS x86_64 (amd64)
|
||||
build/extra/cross-darwin-x86_64/debug: PHONY; $(call run_config_and_build,$@,Debug)
|
||||
build/extra/cross-darwin-x86_64/release: PHONY; $(call run_config_and_build,$@,Release)
|
||||
build/extra/cross-darwin-x86_64/%: export CC = clang -target x86_64-apple-darwin
|
||||
|
||||
4
THANKS
4
THANKS
@ -41,12 +41,14 @@ Joergen Ibsen <jibz@hotmail.com> and d'b
|
||||
for the relocation & address optimization ideas
|
||||
John S. Fine <johnfine@erols.com>
|
||||
for the new version of the dos/exe decompressor
|
||||
Kornel Pal
|
||||
for the EFI support
|
||||
Lukundoo <Lukundoo@softhome.net>
|
||||
for beta testing
|
||||
Michael Devore
|
||||
for initial dos/exe device driver support
|
||||
Oleg V. Volkov <rover@lglobus.ru>
|
||||
for various FreeBSD specific informations
|
||||
for various FreeBSD specific information
|
||||
The Owl & G-RoM
|
||||
for the --compress-icons fix
|
||||
Ralph Roth <RalphRoth@gmx.net>
|
||||
|
||||
@ -160,7 +160,7 @@ Copyright (c) 1996-2023 Markus Oberhumer, Laszlo Molnar & John Reiser
|
||||
|
||||
<p>Info: An "overlay" means auxiliary data attached after the logical end of an executable, and it often contains application specific data (this is a common practice to avoid an extra data file, though it would be better to use resource sections).</p>
|
||||
|
||||
<p><b>UPX</b> handles overlays like many other executable packers do: it simply copies the overlay after the compressed image. This works with some files, but doesn't work with others, depending on how an application actually accesses this overlayed data.</p>
|
||||
<p><b>UPX</b> handles overlays like many other executable packers do: it simply copies the overlay after the compressed image. This works with some files, but doesn't work with others, depending on how an application actually accesses this overlaid data.</p>
|
||||
|
||||
<pre><code>--overlay=copy Copy any extra data attached to the file. [DEFAULT]
|
||||
|
||||
|
||||
@ -153,7 +153,7 @@ OVERLAY HANDLING OPTIONS
|
||||
UPX handles overlays like many other executable packers do: it simply
|
||||
copies the overlay after the compressed image. This works with some
|
||||
files, but doesn't work with others, depending on how an application
|
||||
actually accesses this overlayed data.
|
||||
actually accesses this overlaid data.
|
||||
|
||||
--overlay=copy Copy any extra data attached to the file. [DEFAULT]
|
||||
|
||||
|
||||
@ -296,7 +296,7 @@ it would be better to use resource sections).
|
||||
\&\fB\s-1UPX\s0\fR handles overlays like many other executable packers do: it simply
|
||||
copies the overlay after the compressed image. This works with some
|
||||
files, but doesn't work with others, depending on how an application
|
||||
actually accesses this overlayed data.
|
||||
actually accesses this overlaid data.
|
||||
.PP
|
||||
.Vb 1
|
||||
\& \-\-overlay=copy Copy any extra data attached to the file. [DEFAULT]
|
||||
|
||||
@ -208,7 +208,7 @@ it would be better to use resource sections).
|
||||
B<UPX> handles overlays like many other executable packers do: it simply
|
||||
copies the overlay after the compressed image. This works with some
|
||||
files, but doesn't work with others, depending on how an application
|
||||
actually accesses this overlayed data.
|
||||
actually accesses this overlaid data.
|
||||
|
||||
--overlay=copy Copy any extra data attached to the file. [DEFAULT]
|
||||
|
||||
|
||||
15
src/Makefile
15
src/Makefile
@ -1,9 +1,10 @@
|
||||
#
|
||||
# UPX Makefile - needs GNU make
|
||||
# UPX src Makefile - needs GNU make and CMake >= 3.13
|
||||
#
|
||||
|
||||
# IMPORTANT NOTE: this Makefile is deprecated - please
|
||||
# directly use the CMake build instead!
|
||||
# NOTE: this Makefile is deprecated - please directly use the CMake build
|
||||
# instead. And see the top-level Makefile for some pre-defined CMake
|
||||
# build configurations.
|
||||
|
||||
MAKEFLAGS += -r
|
||||
.SUFFIXES:
|
||||
@ -21,6 +22,7 @@ endif
|
||||
# redirect to top-level CMake build
|
||||
#
|
||||
|
||||
# note that top-level Makefile .DEFAULT_GOAL is build/release
|
||||
.DEFAULT_GOAL = build/debug
|
||||
|
||||
build/debug: $(top_srcdir)/build/debug/upx
|
||||
@ -35,8 +37,10 @@ $(top_srcdir)/build/debug/upx: PHONY
|
||||
$(top_srcdir)/build/release/upx: PHONY
|
||||
$(MAKE) -C $(top_srcdir) build/release
|
||||
|
||||
.NOTPARALLEL: # because the actual builds use "cmake --parallel"
|
||||
.PHONY: PHONY
|
||||
.NOTPARALLEL:
|
||||
.SECONDEXPANSION:
|
||||
.SUFFIXES:
|
||||
|
||||
#
|
||||
# "make run-testsuite"
|
||||
@ -79,9 +83,8 @@ endif
|
||||
# automatically format some C++ source code files
|
||||
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 += conf.h miniacc.h version.h packer_c.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))
|
||||
|
||||
258
src/bele.h
258
src/bele.h
@ -38,35 +38,35 @@
|
||||
// core - NE
|
||||
**************************************************************************/
|
||||
|
||||
static forceinline unsigned get_ne16(const void *p) {
|
||||
static forceinline unsigned get_ne16(const void *p) noexcept {
|
||||
upx_uint16_t v = 0;
|
||||
upx_memcpy_inline(&v, p, sizeof(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
static forceinline unsigned get_ne32(const void *p) {
|
||||
static forceinline unsigned get_ne32(const void *p) noexcept {
|
||||
upx_uint32_t v = 0;
|
||||
upx_memcpy_inline(&v, p, sizeof(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
static forceinline upx_uint64_t get_ne64(const void *p) {
|
||||
static forceinline upx_uint64_t get_ne64(const void *p) noexcept {
|
||||
upx_uint64_t v = 0;
|
||||
upx_memcpy_inline(&v, p, sizeof(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
static forceinline void set_ne16(void *p, unsigned vv) {
|
||||
static forceinline void set_ne16(void *p, unsigned vv) noexcept {
|
||||
upx_uint16_t v = (upx_uint16_t) (vv & 0xffff);
|
||||
upx_memcpy_inline(p, &v, sizeof(v));
|
||||
}
|
||||
|
||||
static forceinline void set_ne32(void *p, unsigned vv) {
|
||||
static forceinline void set_ne32(void *p, unsigned vv) noexcept {
|
||||
upx_uint32_t v = vv;
|
||||
upx_memcpy_inline(p, &v, sizeof(v));
|
||||
}
|
||||
|
||||
static forceinline void set_ne64(void *p, upx_uint64_t vv) {
|
||||
static forceinline void set_ne64(void *p, upx_uint64_t vv) noexcept {
|
||||
upx_uint64_t v = vv;
|
||||
upx_memcpy_inline(p, &v, sizeof(v));
|
||||
}
|
||||
@ -79,31 +79,35 @@ static forceinline void set_ne64(void *p, upx_uint64_t vv) {
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(long) == 4)
|
||||
|
||||
// unfortunately *not* constexpr with MSVC
|
||||
static forceinline unsigned bswap16(unsigned v) { return (unsigned) _byteswap_ulong(v << 16); }
|
||||
static forceinline unsigned bswap32(unsigned v) { return (unsigned) _byteswap_ulong(v); }
|
||||
static forceinline upx_uint64_t bswap64(upx_uint64_t v) { return _byteswap_uint64(v); }
|
||||
// unfortunately *not* constexpr with current MSVC
|
||||
static forceinline unsigned bswap16(unsigned v) noexcept {
|
||||
return (unsigned) _byteswap_ulong(v << 16);
|
||||
}
|
||||
static forceinline unsigned bswap32(unsigned v) noexcept { return (unsigned) _byteswap_ulong(v); }
|
||||
static forceinline upx_uint64_t bswap64(upx_uint64_t v) noexcept { return _byteswap_uint64(v); }
|
||||
|
||||
#else
|
||||
|
||||
static forceinline constexpr unsigned bswap16(unsigned v) {
|
||||
static forceinline constexpr unsigned bswap16(unsigned v) noexcept {
|
||||
// return __builtin_bswap16((upx_uint16_t) (v & 0xffff));
|
||||
// return (unsigned) __builtin_bswap64((upx_uint64_t) v << 48);
|
||||
return __builtin_bswap32(v << 16);
|
||||
}
|
||||
static forceinline constexpr unsigned bswap32(unsigned v) {
|
||||
static forceinline constexpr unsigned bswap32(unsigned v) noexcept {
|
||||
// return (unsigned) __builtin_bswap64((upx_uint64_t) v << 32);
|
||||
return __builtin_bswap32(v);
|
||||
}
|
||||
static forceinline constexpr upx_uint64_t bswap64(upx_uint64_t v) { return __builtin_bswap64(v); }
|
||||
static forceinline constexpr upx_uint64_t bswap64(upx_uint64_t v) noexcept {
|
||||
return __builtin_bswap64(v);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static forceinline constexpr unsigned no_bswap16(unsigned v) {
|
||||
static forceinline constexpr unsigned no_bswap16(unsigned v) noexcept {
|
||||
return v & 0xffff; // needed so that this is equivalent to bswap16() above
|
||||
}
|
||||
static forceinline constexpr unsigned no_bswap32(unsigned v) { return v; }
|
||||
static forceinline constexpr upx_uint64_t no_bswap64(upx_uint64_t v) { return v; }
|
||||
static forceinline constexpr unsigned no_bswap32(unsigned v) noexcept { return v; }
|
||||
static forceinline constexpr upx_uint64_t no_bswap64(upx_uint64_t v) noexcept { return v; }
|
||||
|
||||
#if (ACC_ABI_BIG_ENDIAN)
|
||||
#define ne16_to_be16(v) no_bswap16(v)
|
||||
@ -170,30 +174,27 @@ inline unsigned get_le26(const void *p) { return get_le32(p) & 0x03ffffff; }
|
||||
|
||||
inline void set_le26(void *p, unsigned v) {
|
||||
// preserve the top 6 bits
|
||||
#if 0
|
||||
set_le32(p, (get_le32(p) & 0xfc000000) | (v & 0x03ffffff));
|
||||
#else
|
||||
// set_le32(p, (get_le32(p) & 0xfc000000) | (v & 0x03ffffff));
|
||||
// optimized version, saving a runtime bswap32
|
||||
set_ne32(p, (get_ne32(p) & ne32_to_le32(0xfc000000)) |
|
||||
(ne32_to_le32(v) & ne32_to_le32(0x03ffffff)));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// get signed values
|
||||
**************************************************************************/
|
||||
|
||||
static forceinline int sign_extend(unsigned v, unsigned bits) {
|
||||
static forceinline int sign_extend(unsigned v, unsigned bits) noexcept {
|
||||
const unsigned sign_bit = 1u << (bits - 1);
|
||||
v &= sign_bit | (sign_bit - 1);
|
||||
v |= 0 - (v & sign_bit);
|
||||
v |= 0u - (v & sign_bit);
|
||||
return ACC_ICAST(int, v);
|
||||
}
|
||||
|
||||
static forceinline upx_int64_t sign_extend(upx_uint64_t v, unsigned bits) {
|
||||
static forceinline upx_int64_t sign_extend(upx_uint64_t v, unsigned bits) noexcept {
|
||||
const upx_uint64_t sign_bit = 1ull << (bits - 1);
|
||||
v &= sign_bit | (sign_bit - 1);
|
||||
v |= 0 - (v & sign_bit);
|
||||
v |= 0ull - (v & sign_bit);
|
||||
return ACC_ICAST(upx_int64_t, v);
|
||||
}
|
||||
|
||||
@ -252,359 +253,348 @@ struct alignas(1) BE16 {
|
||||
typedef unsigned integral_conversion_type; // automatic conversion to unsigned
|
||||
byte d[2];
|
||||
|
||||
BE16 &operator=(unsigned v) {
|
||||
BE16 &operator=(unsigned v) noexcept {
|
||||
set_be16(d, v);
|
||||
return *this;
|
||||
}
|
||||
BE16 &operator+=(unsigned v) {
|
||||
BE16 &operator+=(unsigned v) noexcept {
|
||||
set_be16(d, get_be16(d) + v);
|
||||
return *this;
|
||||
}
|
||||
BE16 &operator-=(unsigned v) {
|
||||
BE16 &operator-=(unsigned v) noexcept {
|
||||
set_be16(d, get_be16(d) - v);
|
||||
return *this;
|
||||
}
|
||||
BE16 &operator*=(unsigned v) {
|
||||
BE16 &operator*=(unsigned v) noexcept {
|
||||
set_be16(d, get_be16(d) * v);
|
||||
return *this;
|
||||
}
|
||||
BE16 &operator/=(unsigned v) {
|
||||
BE16 &operator/=(unsigned v) noexcept {
|
||||
set_be16(d, get_be16(d) / v);
|
||||
return *this;
|
||||
}
|
||||
BE16 &operator&=(unsigned v) {
|
||||
BE16 &operator&=(unsigned v) noexcept {
|
||||
set_be16(d, get_be16(d) & v);
|
||||
return *this;
|
||||
}
|
||||
BE16 &operator|=(unsigned v) {
|
||||
BE16 &operator|=(unsigned v) noexcept {
|
||||
set_be16(d, get_be16(d) | v);
|
||||
return *this;
|
||||
}
|
||||
BE16 &operator^=(unsigned v) {
|
||||
BE16 &operator^=(unsigned v) noexcept {
|
||||
set_be16(d, get_be16(d) ^ v);
|
||||
return *this;
|
||||
}
|
||||
BE16 &operator<<=(unsigned v) {
|
||||
BE16 &operator<<=(unsigned v) noexcept {
|
||||
set_be16(d, get_be16(d) << v);
|
||||
return *this;
|
||||
}
|
||||
BE16 &operator>>=(unsigned v) {
|
||||
BE16 &operator>>=(unsigned v) noexcept {
|
||||
set_be16(d, get_be16(d) >> v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator unsigned() const { return get_be16(d); }
|
||||
operator unsigned() const noexcept { return get_be16(d); }
|
||||
|
||||
bool operator<(const BE16 &v) const { return unsigned(*this) < unsigned(v); }
|
||||
bool operator<(const BE16 &v) const noexcept { return unsigned(*this) < unsigned(v); }
|
||||
};
|
||||
|
||||
struct alignas(1) BE32 {
|
||||
typedef unsigned integral_conversion_type; // automatic conversion to unsigned
|
||||
byte d[4];
|
||||
|
||||
BE32 &operator=(unsigned v) {
|
||||
BE32 &operator=(unsigned v) noexcept {
|
||||
set_be32(d, v);
|
||||
return *this;
|
||||
}
|
||||
BE32 &operator+=(unsigned v) {
|
||||
BE32 &operator+=(unsigned v) noexcept {
|
||||
set_be32(d, get_be32(d) + v);
|
||||
return *this;
|
||||
}
|
||||
BE32 &operator-=(unsigned v) {
|
||||
BE32 &operator-=(unsigned v) noexcept {
|
||||
set_be32(d, get_be32(d) - v);
|
||||
return *this;
|
||||
}
|
||||
BE32 &operator*=(unsigned v) {
|
||||
BE32 &operator*=(unsigned v) noexcept {
|
||||
set_be32(d, get_be32(d) * v);
|
||||
return *this;
|
||||
}
|
||||
BE32 &operator/=(unsigned v) {
|
||||
BE32 &operator/=(unsigned v) noexcept {
|
||||
set_be32(d, get_be32(d) / v);
|
||||
return *this;
|
||||
}
|
||||
BE32 &operator&=(unsigned v) {
|
||||
BE32 &operator&=(unsigned v) noexcept {
|
||||
set_be32(d, get_be32(d) & v);
|
||||
return *this;
|
||||
}
|
||||
BE32 &operator|=(unsigned v) {
|
||||
BE32 &operator|=(unsigned v) noexcept {
|
||||
set_be32(d, get_be32(d) | v);
|
||||
return *this;
|
||||
}
|
||||
BE32 &operator^=(unsigned v) {
|
||||
BE32 &operator^=(unsigned v) noexcept {
|
||||
set_be32(d, get_be32(d) ^ v);
|
||||
return *this;
|
||||
}
|
||||
BE32 &operator<<=(unsigned v) {
|
||||
BE32 &operator<<=(unsigned v) noexcept {
|
||||
set_be32(d, get_be32(d) << v);
|
||||
return *this;
|
||||
}
|
||||
BE32 &operator>>=(unsigned v) {
|
||||
BE32 &operator>>=(unsigned v) noexcept {
|
||||
set_be32(d, get_be32(d) >> v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator unsigned() const { return get_be32(d); }
|
||||
operator unsigned() const noexcept { return get_be32(d); }
|
||||
|
||||
bool operator<(const BE32 &v) const { return unsigned(*this) < unsigned(v); }
|
||||
bool operator<(const BE32 &v) const noexcept { return unsigned(*this) < unsigned(v); }
|
||||
};
|
||||
|
||||
struct alignas(1) BE64 {
|
||||
typedef upx_uint64_t integral_conversion_type; // automatic conversion to upx_uint64_t
|
||||
byte d[8];
|
||||
|
||||
BE64 &operator=(upx_uint64_t v) {
|
||||
BE64 &operator=(upx_uint64_t v) noexcept {
|
||||
set_be64(d, v);
|
||||
return *this;
|
||||
}
|
||||
BE64 &operator+=(upx_uint64_t v) {
|
||||
BE64 &operator+=(upx_uint64_t v) noexcept {
|
||||
set_be64(d, get_be64(d) + v);
|
||||
return *this;
|
||||
}
|
||||
BE64 &operator-=(upx_uint64_t v) {
|
||||
BE64 &operator-=(upx_uint64_t v) noexcept {
|
||||
set_be64(d, get_be64(d) - v);
|
||||
return *this;
|
||||
}
|
||||
BE64 &operator*=(upx_uint64_t v) {
|
||||
BE64 &operator*=(upx_uint64_t v) noexcept {
|
||||
set_be64(d, get_be64(d) * v);
|
||||
return *this;
|
||||
}
|
||||
BE64 &operator/=(upx_uint64_t v) {
|
||||
BE64 &operator/=(upx_uint64_t v) noexcept {
|
||||
set_be64(d, get_be64(d) / v);
|
||||
return *this;
|
||||
}
|
||||
BE64 &operator&=(upx_uint64_t v) {
|
||||
BE64 &operator&=(upx_uint64_t v) noexcept {
|
||||
set_be64(d, get_be64(d) & v);
|
||||
return *this;
|
||||
}
|
||||
BE64 &operator|=(upx_uint64_t v) {
|
||||
BE64 &operator|=(upx_uint64_t v) noexcept {
|
||||
set_be64(d, get_be64(d) | v);
|
||||
return *this;
|
||||
}
|
||||
BE64 &operator^=(upx_uint64_t v) {
|
||||
BE64 &operator^=(upx_uint64_t v) noexcept {
|
||||
set_be64(d, get_be64(d) ^ v);
|
||||
return *this;
|
||||
}
|
||||
BE64 &operator<<=(unsigned v) {
|
||||
BE64 &operator<<=(unsigned v) noexcept {
|
||||
set_be64(d, get_be64(d) << v);
|
||||
return *this;
|
||||
}
|
||||
BE64 &operator>>=(unsigned v) {
|
||||
BE64 &operator>>=(unsigned v) noexcept {
|
||||
set_be64(d, get_be64(d) >> v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator upx_uint64_t() const { return get_be64(d); }
|
||||
operator upx_uint64_t() const noexcept { return get_be64(d); }
|
||||
|
||||
bool operator<(const BE64 &v) const { return upx_uint64_t(*this) < upx_uint64_t(v); }
|
||||
bool operator<(const BE64 &v) const noexcept { return upx_uint64_t(*this) < upx_uint64_t(v); }
|
||||
};
|
||||
|
||||
struct alignas(1) LE16 {
|
||||
typedef unsigned integral_conversion_type; // automatic conversion to unsigned
|
||||
byte d[2];
|
||||
|
||||
LE16 &operator=(unsigned v) {
|
||||
LE16 &operator=(unsigned v) noexcept {
|
||||
set_le16(d, v);
|
||||
return *this;
|
||||
}
|
||||
LE16 &operator+=(unsigned v) {
|
||||
LE16 &operator+=(unsigned v) noexcept {
|
||||
set_le16(d, get_le16(d) + v);
|
||||
return *this;
|
||||
}
|
||||
LE16 &operator-=(unsigned v) {
|
||||
LE16 &operator-=(unsigned v) noexcept {
|
||||
set_le16(d, get_le16(d) - v);
|
||||
return *this;
|
||||
}
|
||||
LE16 &operator*=(unsigned v) {
|
||||
LE16 &operator*=(unsigned v) noexcept {
|
||||
set_le16(d, get_le16(d) * v);
|
||||
return *this;
|
||||
}
|
||||
LE16 &operator/=(unsigned v) {
|
||||
LE16 &operator/=(unsigned v) noexcept {
|
||||
set_le16(d, get_le16(d) / v);
|
||||
return *this;
|
||||
}
|
||||
LE16 &operator&=(unsigned v) {
|
||||
LE16 &operator&=(unsigned v) noexcept {
|
||||
set_le16(d, get_le16(d) & v);
|
||||
return *this;
|
||||
}
|
||||
LE16 &operator|=(unsigned v) {
|
||||
LE16 &operator|=(unsigned v) noexcept {
|
||||
set_le16(d, get_le16(d) | v);
|
||||
return *this;
|
||||
}
|
||||
LE16 &operator^=(unsigned v) {
|
||||
LE16 &operator^=(unsigned v) noexcept {
|
||||
set_le16(d, get_le16(d) ^ v);
|
||||
return *this;
|
||||
}
|
||||
LE16 &operator<<=(unsigned v) {
|
||||
LE16 &operator<<=(unsigned v) noexcept {
|
||||
set_le16(d, get_le16(d) << v);
|
||||
return *this;
|
||||
}
|
||||
LE16 &operator>>=(unsigned v) {
|
||||
LE16 &operator>>=(unsigned v) noexcept {
|
||||
set_le16(d, get_le16(d) >> v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator unsigned() const { return get_le16(d); }
|
||||
operator unsigned() const noexcept { return get_le16(d); }
|
||||
|
||||
bool operator<(const LE16 &v) const { return unsigned(*this) < unsigned(v); }
|
||||
bool operator<(const LE16 &v) const noexcept { return unsigned(*this) < unsigned(v); }
|
||||
};
|
||||
|
||||
struct alignas(1) LE32 {
|
||||
typedef unsigned integral_conversion_type; // automatic conversion to unsigned
|
||||
byte d[4];
|
||||
|
||||
LE32 &operator=(unsigned v) {
|
||||
LE32 &operator=(unsigned v) noexcept {
|
||||
set_le32(d, v);
|
||||
return *this;
|
||||
}
|
||||
LE32 &operator+=(unsigned v) {
|
||||
LE32 &operator+=(unsigned v) noexcept {
|
||||
set_le32(d, get_le32(d) + v);
|
||||
return *this;
|
||||
}
|
||||
LE32 &operator-=(unsigned v) {
|
||||
LE32 &operator-=(unsigned v) noexcept {
|
||||
set_le32(d, get_le32(d) - v);
|
||||
return *this;
|
||||
}
|
||||
LE32 &operator*=(unsigned v) {
|
||||
LE32 &operator*=(unsigned v) noexcept {
|
||||
set_le32(d, get_le32(d) * v);
|
||||
return *this;
|
||||
}
|
||||
LE32 &operator/=(unsigned v) {
|
||||
LE32 &operator/=(unsigned v) noexcept {
|
||||
set_le32(d, get_le32(d) / v);
|
||||
return *this;
|
||||
}
|
||||
LE32 &operator&=(unsigned v) {
|
||||
LE32 &operator&=(unsigned v) noexcept {
|
||||
set_le32(d, get_le32(d) & v);
|
||||
return *this;
|
||||
}
|
||||
LE32 &operator|=(unsigned v) {
|
||||
LE32 &operator|=(unsigned v) noexcept {
|
||||
set_le32(d, get_le32(d) | v);
|
||||
return *this;
|
||||
}
|
||||
LE32 &operator^=(unsigned v) {
|
||||
LE32 &operator^=(unsigned v) noexcept {
|
||||
set_le32(d, get_le32(d) ^ v);
|
||||
return *this;
|
||||
}
|
||||
LE32 &operator<<=(unsigned v) {
|
||||
LE32 &operator<<=(unsigned v) noexcept {
|
||||
set_le32(d, get_le32(d) << v);
|
||||
return *this;
|
||||
}
|
||||
LE32 &operator>>=(unsigned v) {
|
||||
LE32 &operator>>=(unsigned v) noexcept {
|
||||
set_le32(d, get_le32(d) >> v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator unsigned() const { return get_le32(d); }
|
||||
operator unsigned() const noexcept { return get_le32(d); }
|
||||
|
||||
bool operator<(const LE32 &v) const { return unsigned(*this) < unsigned(v); }
|
||||
bool operator<(const LE32 &v) const noexcept { return unsigned(*this) < unsigned(v); }
|
||||
};
|
||||
|
||||
struct alignas(1) LE64 {
|
||||
typedef upx_uint64_t integral_conversion_type; // automatic conversion to upx_uint64_t
|
||||
byte d[8];
|
||||
|
||||
LE64 &operator=(upx_uint64_t v) {
|
||||
LE64 &operator=(upx_uint64_t v) noexcept {
|
||||
set_le64(d, v);
|
||||
return *this;
|
||||
}
|
||||
LE64 &operator+=(upx_uint64_t v) {
|
||||
LE64 &operator+=(upx_uint64_t v) noexcept {
|
||||
set_le64(d, get_le64(d) + v);
|
||||
return *this;
|
||||
}
|
||||
LE64 &operator-=(upx_uint64_t v) {
|
||||
LE64 &operator-=(upx_uint64_t v) noexcept {
|
||||
set_le64(d, get_le64(d) - v);
|
||||
return *this;
|
||||
}
|
||||
LE64 &operator*=(upx_uint64_t v) {
|
||||
LE64 &operator*=(upx_uint64_t v) noexcept {
|
||||
set_le64(d, get_le64(d) * v);
|
||||
return *this;
|
||||
}
|
||||
LE64 &operator/=(upx_uint64_t v) {
|
||||
LE64 &operator/=(upx_uint64_t v) noexcept {
|
||||
set_le64(d, get_le64(d) / v);
|
||||
return *this;
|
||||
}
|
||||
LE64 &operator&=(upx_uint64_t v) {
|
||||
LE64 &operator&=(upx_uint64_t v) noexcept {
|
||||
set_le64(d, get_le64(d) & v);
|
||||
return *this;
|
||||
}
|
||||
LE64 &operator|=(upx_uint64_t v) {
|
||||
LE64 &operator|=(upx_uint64_t v) noexcept {
|
||||
set_le64(d, get_le64(d) | v);
|
||||
return *this;
|
||||
}
|
||||
LE64 &operator^=(upx_uint64_t v) {
|
||||
LE64 &operator^=(upx_uint64_t v) noexcept {
|
||||
set_le64(d, get_le64(d) ^ v);
|
||||
return *this;
|
||||
}
|
||||
LE64 &operator<<=(unsigned v) {
|
||||
LE64 &operator<<=(unsigned v) noexcept {
|
||||
set_le64(d, get_le64(d) << v);
|
||||
return *this;
|
||||
}
|
||||
LE64 &operator>>=(unsigned v) {
|
||||
LE64 &operator>>=(unsigned v) noexcept {
|
||||
set_le64(d, get_le64(d) >> v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator upx_uint64_t() const { return get_le64(d); }
|
||||
operator upx_uint64_t() const noexcept { return get_le64(d); }
|
||||
|
||||
bool operator<(const LE64 &v) const { return upx_uint64_t(*this) < upx_uint64_t(v); }
|
||||
bool operator<(const LE64 &v) const noexcept { return upx_uint64_t(*this) < upx_uint64_t(v); }
|
||||
};
|
||||
|
||||
// native types
|
||||
#if (ACC_ABI_BIG_ENDIAN)
|
||||
typedef BE16 NE16;
|
||||
typedef BE32 NE32;
|
||||
typedef BE64 NE64;
|
||||
#else
|
||||
typedef LE16 NE16;
|
||||
typedef LE32 NE32;
|
||||
typedef LE64 NE64;
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
// global operators (pointer addition/subtraction)
|
||||
**************************************************************************/
|
||||
|
||||
template <class T>
|
||||
inline T *operator+(T *ptr, const BE16 &v) {
|
||||
inline T *operator+(T *ptr, const BE16 &v) noexcept {
|
||||
return ptr + unsigned(v);
|
||||
}
|
||||
template <class T>
|
||||
inline T *operator-(T *ptr, const BE16 &v) {
|
||||
inline T *operator-(T *ptr, const BE16 &v) noexcept {
|
||||
return ptr - unsigned(v);
|
||||
}
|
||||
template <class T>
|
||||
inline T *operator+(T *ptr, const BE32 &v) {
|
||||
inline T *operator+(T *ptr, const BE32 &v) noexcept {
|
||||
return ptr + unsigned(v);
|
||||
}
|
||||
template <class T>
|
||||
inline T *operator-(T *ptr, const BE32 &v) {
|
||||
inline T *operator-(T *ptr, const BE32 &v) noexcept {
|
||||
return ptr - unsigned(v);
|
||||
}
|
||||
template <class T>
|
||||
inline T *operator+(T *ptr, const LE16 &v) {
|
||||
inline T *operator+(T *ptr, const LE16 &v) noexcept {
|
||||
return ptr + unsigned(v);
|
||||
}
|
||||
template <class T>
|
||||
inline T *operator-(T *ptr, const LE16 &v) {
|
||||
inline T *operator-(T *ptr, const LE16 &v) noexcept {
|
||||
return ptr - unsigned(v);
|
||||
}
|
||||
template <class T>
|
||||
inline T *operator+(T *ptr, const LE32 &v) {
|
||||
inline T *operator+(T *ptr, const LE32 &v) noexcept {
|
||||
return ptr + unsigned(v);
|
||||
}
|
||||
template <class T>
|
||||
inline T *operator-(T *ptr, const LE32 &v) {
|
||||
inline T *operator-(T *ptr, const LE32 &v) noexcept {
|
||||
return ptr - unsigned(v);
|
||||
}
|
||||
|
||||
// these are not implemented on purpose and will cause errors
|
||||
template <class T>
|
||||
T *operator+(T *ptr, const BE64 &v) DELETED_FUNCTION;
|
||||
T *operator+(T *ptr, const BE64 &v) noexcept DELETED_FUNCTION;
|
||||
template <class T>
|
||||
T *operator-(T *ptr, const BE64 &v) DELETED_FUNCTION;
|
||||
T *operator-(T *ptr, const BE64 &v) noexcept DELETED_FUNCTION;
|
||||
template <class T>
|
||||
T *operator+(T *ptr, const LE64 &v) DELETED_FUNCTION;
|
||||
T *operator+(T *ptr, const LE64 &v) noexcept DELETED_FUNCTION;
|
||||
template <class T>
|
||||
T *operator-(T *ptr, const LE64 &v) DELETED_FUNCTION;
|
||||
T *operator-(T *ptr, const LE64 &v) noexcept DELETED_FUNCTION;
|
||||
|
||||
/*************************************************************************
|
||||
// global overloads
|
||||
@ -644,6 +634,19 @@ inline unsigned UPX_MIN(const LE32 &a, unsigned b) { return UPX_MIN(unsigned(a),
|
||||
// misc support
|
||||
**************************************************************************/
|
||||
|
||||
template <>
|
||||
struct upx_is_integral<BE16> : public std::true_type {};
|
||||
template <>
|
||||
struct upx_is_integral<BE32> : public std::true_type {};
|
||||
template <>
|
||||
struct upx_is_integral<BE64> : public std::true_type {};
|
||||
template <>
|
||||
struct upx_is_integral<LE16> : public std::true_type {};
|
||||
template <>
|
||||
struct upx_is_integral<LE32> : public std::true_type {};
|
||||
template <>
|
||||
struct upx_is_integral<LE64> : public std::true_type {};
|
||||
|
||||
// for use with qsort()
|
||||
extern "C" {
|
||||
int __acc_cdecl_qsort be16_compare(const void *, const void *);
|
||||
@ -664,6 +667,23 @@ int __acc_cdecl_qsort le32_compare_signed(const void *, const void *);
|
||||
int __acc_cdecl_qsort le64_compare_signed(const void *, const void *);
|
||||
} // extern "C"
|
||||
|
||||
// native types
|
||||
#if (ACC_ABI_BIG_ENDIAN)
|
||||
typedef BE16 NE16;
|
||||
typedef BE32 NE32;
|
||||
typedef BE64 NE64;
|
||||
#define ne16_compare be16_compare
|
||||
#define ne32_compare be32_compare
|
||||
#define ne64_compare be64_compare
|
||||
#else
|
||||
typedef LE16 NE16;
|
||||
typedef LE32 NE32;
|
||||
typedef LE64 NE64;
|
||||
#define ne16_compare le16_compare
|
||||
#define ne32_compare le32_compare
|
||||
#define ne64_compare le64_compare
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
// Provide namespaces and classes to abstract endianness policies.
|
||||
//
|
||||
|
||||
@ -37,20 +37,20 @@
|
||||
// CTP - Compile-Time Polymorphism (templates)
|
||||
#define V static inline
|
||||
#define S static int __acc_cdecl_qsort
|
||||
#define C /*empty*/
|
||||
#define C noexcept
|
||||
#elif defined(BELE_RTP)
|
||||
// RTP - Run-Time Polymorphism (virtual functions)
|
||||
#define V virtual
|
||||
#define S virtual int
|
||||
#define C const
|
||||
#define C const noexcept
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
|
||||
#if defined(BELE_RTP)
|
||||
struct AbstractPolicy {
|
||||
inline AbstractPolicy() {}
|
||||
virtual inline ~AbstractPolicy() {}
|
||||
inline AbstractPolicy() noexcept {}
|
||||
virtual inline ~AbstractPolicy() noexcept {}
|
||||
V bool isBE() C = 0;
|
||||
V bool isLE() C = 0;
|
||||
|
||||
@ -91,7 +91,7 @@ private:
|
||||
|
||||
#if defined(BELE_RTP)
|
||||
#undef C
|
||||
#define C const override
|
||||
#define C const noexcept override
|
||||
#endif
|
||||
|
||||
struct BEPolicy
|
||||
@ -99,7 +99,7 @@ struct BEPolicy
|
||||
final : public AbstractPolicy
|
||||
#endif
|
||||
{
|
||||
inline BEPolicy() {}
|
||||
inline BEPolicy() noexcept {}
|
||||
#if defined(BELE_CTP)
|
||||
typedef N_BELE_RTP::BEPolicy RTP_Policy;
|
||||
#elif defined(BELE_RTP)
|
||||
@ -160,7 +160,7 @@ struct LEPolicy
|
||||
final : public AbstractPolicy
|
||||
#endif
|
||||
{
|
||||
inline LEPolicy() {}
|
||||
inline LEPolicy() noexcept {}
|
||||
#if defined(BELE_CTP)
|
||||
typedef N_BELE_RTP::LEPolicy RTP_Policy;
|
||||
#elif defined(BELE_RTP)
|
||||
@ -225,24 +225,6 @@ typedef LEPolicy HostPolicy;
|
||||
#error "ACC_ABI_ENDIAN"
|
||||
#endif
|
||||
|
||||
#if 0 /* UNUSED */
|
||||
struct HostAlignedPolicy {
|
||||
#if defined(BELE_CTP)
|
||||
enum { isBE = HostPolicy::isBE, isLE = HostPolicy::isLE };
|
||||
#endif
|
||||
|
||||
typedef upx_uint16_t U16;
|
||||
typedef upx_uint32_t U32;
|
||||
typedef upx_uint64_t U64;
|
||||
|
||||
static void compileTimeAssertions() {
|
||||
COMPILE_TIME_ASSERT(sizeof(U16) == 2)
|
||||
COMPILE_TIME_ASSERT(sizeof(U32) == 4)
|
||||
COMPILE_TIME_ASSERT(sizeof(U64) == 8)
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#undef V
|
||||
#undef S
|
||||
#undef C
|
||||
|
||||
@ -39,7 +39,7 @@ int upx_doctest_check(int argc, char **argv) {
|
||||
const char *e = getenv("UPX_DEBUG_DOCTEST_DISABLE");
|
||||
if (e && e[0] && strcmp(e, "0") != 0)
|
||||
return 0;
|
||||
bool minimal = true; // only show failing tests
|
||||
bool minimal = true; // don't show summary
|
||||
bool duration = false; // show timings
|
||||
bool success = false; // show all tests
|
||||
#if DEBUG
|
||||
@ -47,12 +47,13 @@ int upx_doctest_check(int argc, char **argv) {
|
||||
#endif
|
||||
e = getenv("UPX_DEBUG_DOCTEST_VERBOSE");
|
||||
if (e && e[0]) {
|
||||
minimal = false;
|
||||
if (strcmp(e, "0") == 0) {
|
||||
minimal = true;
|
||||
} else if (strcmp(e, "2") == 0) {
|
||||
minimal = false;
|
||||
duration = true;
|
||||
} else if (strcmp(e, "3") == 0) {
|
||||
minimal = false;
|
||||
duration = true;
|
||||
success = true;
|
||||
}
|
||||
@ -100,6 +101,7 @@ ACC_COMPILE_TIME_ASSERT_HEADER(bswap64(0x0807060504030201ull) == 0x0102030405060
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("") == 0)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("a") == 1)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_len("ab") == 2)
|
||||
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(compile_time::string_eq("", ""))
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(!compile_time::string_eq("a", ""))
|
||||
@ -145,15 +147,18 @@ namespace {
|
||||
|
||||
template <class T>
|
||||
struct TestBELE {
|
||||
__acc_static_noinline bool test(void) {
|
||||
static noinline bool test(void) {
|
||||
// POD checks
|
||||
{
|
||||
COMPILE_TIME_ASSERT(std::is_standard_layout<T>::value)
|
||||
COMPILE_TIME_ASSERT(std::is_trivial<T>::value)
|
||||
// extra checks, these are probably implied by std::is_trivial:
|
||||
// extra checks, these are probably implied by std::is_trivial
|
||||
COMPILE_TIME_ASSERT(std::is_nothrow_default_constructible<T>::value)
|
||||
COMPILE_TIME_ASSERT(std::is_trivially_copyable<T>::value)
|
||||
COMPILE_TIME_ASSERT(std::is_trivially_default_constructible<T>::value)
|
||||
// UPX
|
||||
COMPILE_TIME_ASSERT(upx_is_integral<T>::value)
|
||||
COMPILE_TIME_ASSERT(upx_is_integral_v<T>)
|
||||
}
|
||||
// alignment checks
|
||||
{
|
||||
@ -177,8 +182,7 @@ struct TestBELE {
|
||||
UNUSED(t1);
|
||||
UNUSED(t2);
|
||||
}
|
||||
#if 1
|
||||
// arithmetic checks
|
||||
// arithmetic checks (modern compilers will optimize this away)
|
||||
{
|
||||
T allbits;
|
||||
allbits = 0;
|
||||
@ -187,6 +191,7 @@ struct TestBELE {
|
||||
T v1;
|
||||
v1 = 1;
|
||||
v1 *= 2;
|
||||
v1 /= 1;
|
||||
v1 -= 1;
|
||||
T v2;
|
||||
v2 = 1;
|
||||
@ -217,14 +222,13 @@ struct TestBELE {
|
||||
if ((v1 ^ v2) != 1)
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <class A, class B>
|
||||
struct TestNoAliasingStruct {
|
||||
__acc_static_noinline bool test(A *a, B *b) {
|
||||
static noinline bool test(A *a, B *b) {
|
||||
*a = 0;
|
||||
*b = 0;
|
||||
*b -= 3;
|
||||
@ -232,7 +236,7 @@ struct TestNoAliasingStruct {
|
||||
}
|
||||
};
|
||||
template <class A, class B>
|
||||
__acc_static_forceinline bool testNoAliasing(A *a, B *b) {
|
||||
static forceinline bool testNoAliasing(A *a, B *b) {
|
||||
return TestNoAliasingStruct<A, B>::test(a, b);
|
||||
}
|
||||
template <class T>
|
||||
@ -274,6 +278,10 @@ void upx_compiler_sanity_check(void) {
|
||||
COMPILE_TIME_ASSERT_ALIGNED1(LE32)
|
||||
COMPILE_TIME_ASSERT_ALIGNED1(LE64)
|
||||
|
||||
COMPILE_TIME_ASSERT(sizeof(upx_charptr_unit_type) == 1)
|
||||
COMPILE_TIME_ASSERT_ALIGNED1(upx_charptr_unit_type)
|
||||
COMPILE_TIME_ASSERT(sizeof(*((charptr) nullptr)) == 1)
|
||||
|
||||
COMPILE_TIME_ASSERT(sizeof(UPX_VERSION_STRING4) == 4 + 1)
|
||||
assert(strlen(UPX_VERSION_STRING4) == 4);
|
||||
COMPILE_TIME_ASSERT(sizeof(UPX_VERSION_YEAR) == 4 + 1)
|
||||
@ -293,7 +301,7 @@ void upx_compiler_sanity_check(void) {
|
||||
}
|
||||
assert(UPX_RSIZE_MAX_MEM == 805306368);
|
||||
|
||||
#if 1
|
||||
#if DEBUG || 1
|
||||
assert(TestBELE<LE16>::test());
|
||||
assert(TestBELE<LE32>::test());
|
||||
assert(TestBELE<LE64>::test());
|
||||
@ -354,9 +362,9 @@ void upx_compiler_sanity_check(void) {
|
||||
assert(dd == ne32_to_le32(0xf7020304));
|
||||
}
|
||||
{
|
||||
upx_uint16_t a;
|
||||
upx_uint32_t b;
|
||||
upx_uint64_t c;
|
||||
upx_uint16_t a = 0;
|
||||
upx_uint32_t b = 0;
|
||||
upx_uint64_t c = 0;
|
||||
set_ne16(&a, 0x04030201); // ignore upper bits
|
||||
set_ne32(&b, 0x04030201);
|
||||
set_ne64(&c, 0x0807060504030201ull);
|
||||
@ -454,7 +462,7 @@ TEST_CASE("working -fno-strict-overflow") {
|
||||
}
|
||||
|
||||
TEST_CASE("libc snprintf") {
|
||||
// runtime check that Win32/MinGW <stdio.h> works as expected
|
||||
// runtime check that Windows/MinGW <stdio.h> works as expected
|
||||
char buf[64];
|
||||
long long ll = acc_vget_int(-1, 0);
|
||||
unsigned long long llu = (unsigned long long) ll;
|
||||
|
||||
@ -29,23 +29,30 @@
|
||||
**************************************************************************/
|
||||
|
||||
#define DOCTEST_CONFIG_IMPLEMENT
|
||||
#if !defined(UPX_DOCTEST_CONFIG_MULTITHREADING)
|
||||
#define DOCTEST_CONFIG_NO_MULTITHREADING
|
||||
#endif
|
||||
#define DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
|
||||
|
||||
#if !defined(DOCTEST_CONFIG_DISABLE)
|
||||
|
||||
#if defined(__i386__) && defined(__MSDOS__) && defined(__DJGPP__) && defined(__GNUC__)
|
||||
#define DOCTEST_CONFIG_NO_MULTITHREADING
|
||||
#define DOCTEST_CONFIG_NO_POSIX_SIGNALS
|
||||
#elif defined(__m68k__) && defined(__atarist__) && defined(__GNUC__)
|
||||
#define DOCTEST_CONFIG_COLORS_NONE
|
||||
#define DOCTEST_CONFIG_NO_MULTITHREADING
|
||||
#define DOCTEST_CONFIG_NO_POSIX_SIGNALS
|
||||
#pragma GCC diagnostic ignored "-Wshadow"
|
||||
#endif
|
||||
#define DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
|
||||
#if !defined(DOCTEST_CONFIG_DISABLE)
|
||||
|
||||
#if !defined(UPX_DOCTEST_CONFIG_MULTITHREADING)
|
||||
#define DOCTEST_CONFIG_NO_MULTITHREADING
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) && defined(__FAST_MATH__) && defined(__INTEL_LLVM_COMPILER)
|
||||
// warning: comparison with NaN always evaluates to false in fast floating point modes
|
||||
#pragma clang diagnostic ignored "-Wtautological-constant-compare"
|
||||
#endif
|
||||
|
||||
#include <doctest/doctest/parts/doctest.cpp>
|
||||
#endif
|
||||
#endif // DOCTEST_CONFIG_DISABLE
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
|
||||
@ -91,6 +91,17 @@ TEST_CASE("basic xspan usage") {
|
||||
CHECK_NOTHROW(raw_bytes(a0, 0));
|
||||
CHECK_THROWS(raw_bytes(a0, 1));
|
||||
CHECK_THROWS(raw_index_bytes(a0, 0, 0));
|
||||
|
||||
CHECK(raw_bytes(b0, 0) == buf);
|
||||
CHECK(raw_bytes(bp, 0) == buf);
|
||||
// info: these will fail if we ever add an overload for bounded-arrays
|
||||
#if WITH_XSPAN >= 2
|
||||
CHECK(b0.raw_size_in_bytes() == 0u);
|
||||
CHECK(bp.raw_size_in_bytes() == 0u);
|
||||
#endif
|
||||
CHECK(raw_bytes(b0, 999999) == buf);
|
||||
CHECK(raw_bytes(bp, 999999) == buf);
|
||||
|
||||
CHECK(raw_bytes(c0, 4) == buf);
|
||||
CHECK(raw_index_bytes(c0, 1, 3) == buf + 1);
|
||||
CHECK(raw_bytes(cp, 4) == buf);
|
||||
@ -136,6 +147,17 @@ TEST_CASE("basic xspan usage") {
|
||||
CHECK_NOTHROW(raw_bytes(a0, 0));
|
||||
CHECK_THROWS(raw_bytes(a0, 1));
|
||||
CHECK_THROWS(raw_index_bytes(a0, 0, 0));
|
||||
|
||||
CHECK(raw_bytes(b0, 0) == buf);
|
||||
CHECK(raw_bytes(bp, 0) == buf);
|
||||
// info: these will fail if we ever add an overload for bounded-arrays
|
||||
#if WITH_XSPAN >= 2
|
||||
CHECK(b0.raw_size_in_bytes() == 0u);
|
||||
CHECK(bp.raw_size_in_bytes() == 0u);
|
||||
#endif
|
||||
CHECK(raw_bytes(b0, 999999) == buf);
|
||||
CHECK(raw_bytes(bp, 999999) == buf);
|
||||
|
||||
CHECK(raw_bytes(c0, 4) == buf);
|
||||
CHECK(raw_index_bytes(c0, 1, 3) == buf + 1);
|
||||
CHECK(raw_bytes(cp, 4) == buf);
|
||||
|
||||
@ -78,7 +78,7 @@ int upx_compress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsigned
|
||||
// force users to provide *dst_len
|
||||
assert(*dst_len != 0);
|
||||
#endif
|
||||
// for UPX, we always require a reasonably sized outbut buffer
|
||||
// for UPX, we always require a reasonably sized output buffer
|
||||
assert(*dst_len >= MemBuffer::getSizeForCompression(src_len));
|
||||
|
||||
if (!cresult)
|
||||
|
||||
@ -116,7 +116,7 @@ static bool prepare_result(lzma_compress_result_t *res, unsigned src_len, int me
|
||||
res->lit_context_bits = (method >> 8) & 15;
|
||||
}
|
||||
#if 0
|
||||
// DEBUG - set sizes so that we use a maxmimum amount of stack.
|
||||
// DEBUG - set sizes so that we use a maximum amount of stack.
|
||||
// These settings cause res->num_probs == 3147574, i.e. we will
|
||||
// need about 6 MiB of stack during runtime decompression.
|
||||
res->lit_pos_bits = 4;
|
||||
@ -524,13 +524,12 @@ const char *upx_lzma_version_string(void) { return "4.43"; }
|
||||
**************************************************************************/
|
||||
|
||||
TEST_CASE("upx_lzma_decompress") {
|
||||
typedef const upx_byte C;
|
||||
C *c_data;
|
||||
upx_byte d_buf[16];
|
||||
const byte *c_data;
|
||||
byte d_buf[16];
|
||||
unsigned d_len;
|
||||
int r;
|
||||
|
||||
c_data = (C *) "\x1a\x03\x00\x7f\xed\x3c\x00\x00\x00";
|
||||
c_data = (const byte *) "\x1a\x03\x00\x7f\xed\x3c\x00\x00\x00";
|
||||
d_len = 16;
|
||||
r = upx_lzma_decompress(c_data, 9, d_buf, &d_len, M_LZMA, nullptr);
|
||||
CHECK((r == 0 && d_len == 16));
|
||||
|
||||
@ -113,14 +113,14 @@ int upx_ucl_compress(const upx_bytep src, unsigned src_len, upx_bytep dst, unsig
|
||||
cconf.bb_endian = 0;
|
||||
cconf.bb_size = 0;
|
||||
if (method >= M_NRV2B_LE32 && method <= M_NRV2E_LE16) {
|
||||
static const unsigned char sizes[3] = {32, 8, 16};
|
||||
static const upx_uint8_t sizes[3] = {32, 8, 16};
|
||||
cconf.bb_size = sizes[(method - M_NRV2B_LE32) % 3];
|
||||
} else {
|
||||
throwInternalError("unknown compression method");
|
||||
return UPX_E_ERROR;
|
||||
}
|
||||
|
||||
// optimize compression parms
|
||||
// optimize compression params
|
||||
if (level <= 3 && cconf.max_offset == UCL_UINT_MAX)
|
||||
cconf.max_offset = 8 * 1024 - 1;
|
||||
else if (level == 4 && cconf.max_offset == UCL_UINT_MAX)
|
||||
@ -241,9 +241,9 @@ int upx_ucl_test_overlap(const upx_bytep buf, const upx_bytep tbuf, unsigned src
|
||||
**************************************************************************/
|
||||
|
||||
extern "C" {
|
||||
static ucl_voidp __UCL_CDECL my_malloc(ucl_uint n) { return calloc(1, n); }
|
||||
static ucl_voidp __UCL_CDECL my_malloc(ucl_uint n) { return upx_calloc(n, 1); }
|
||||
static void __UCL_CDECL my_free(ucl_voidp p) { free(p); }
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
int upx_ucl_init(void) {
|
||||
if (ucl_init() != UCL_E_OK)
|
||||
@ -327,13 +327,12 @@ TEST_CASE("compress_ucl") {
|
||||
#endif // DEBUG
|
||||
|
||||
TEST_CASE("upx_ucl_decompress") {
|
||||
typedef const upx_byte C;
|
||||
C *c_data;
|
||||
upx_byte d_buf[16];
|
||||
const byte *c_data;
|
||||
byte d_buf[16];
|
||||
unsigned d_len;
|
||||
int r;
|
||||
|
||||
c_data = (C *) "\x92\xff\x10\x00\x00\x00\x00\x00\x48\xff";
|
||||
c_data = (const byte *) "\x92\xff\x10\x00\x00\x00\x00\x00\x48\xff";
|
||||
d_len = 16;
|
||||
r = upx_ucl_decompress(c_data, 10, d_buf, &d_len, M_NRV2B_8, nullptr);
|
||||
CHECK((r == 0 && d_len == 16));
|
||||
@ -343,7 +342,7 @@ TEST_CASE("upx_ucl_decompress") {
|
||||
r = upx_ucl_decompress(c_data, 10, d_buf, &d_len, M_NRV2B_8, nullptr);
|
||||
CHECK(r == UPX_E_OUTPUT_OVERRUN);
|
||||
|
||||
c_data = (C *) "\x92\xff\x10\x92\x49\x24\x92\xa0\xff";
|
||||
c_data = (const byte *) "\x92\xff\x10\x92\x49\x24\x92\xa0\xff";
|
||||
d_len = 16;
|
||||
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2D_8, nullptr);
|
||||
CHECK((r == 0 && d_len == 16));
|
||||
@ -353,7 +352,7 @@ TEST_CASE("upx_ucl_decompress") {
|
||||
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2D_8, nullptr);
|
||||
CHECK(r == UPX_E_OUTPUT_OVERRUN);
|
||||
|
||||
c_data = (C *) "\x90\xff\xb0\x92\x49\x24\x92\xa0\xff";
|
||||
c_data = (const byte *) "\x90\xff\xb0\x92\x49\x24\x92\xa0\xff";
|
||||
d_len = 16;
|
||||
r = upx_ucl_decompress(c_data, 9, d_buf, &d_len, M_NRV2E_8, nullptr);
|
||||
CHECK((r == 0 && d_len == 16));
|
||||
|
||||
@ -287,13 +287,12 @@ TEST_CASE("compress_zlib") {
|
||||
#endif // DEBUG
|
||||
|
||||
TEST_CASE("upx_zlib_decompress") {
|
||||
typedef const upx_byte C;
|
||||
C *c_data;
|
||||
upx_byte d_buf[16];
|
||||
const byte *c_data;
|
||||
byte d_buf[16];
|
||||
unsigned d_len;
|
||||
int r;
|
||||
|
||||
c_data = (C *) "\xfb\xff\x1f\x15\x00\x00";
|
||||
c_data = (const byte *) "\xfb\xff\x1f\x15\x00\x00";
|
||||
d_len = 16;
|
||||
r = upx_zlib_decompress(c_data, 6, d_buf, &d_len, M_DEFLATE, nullptr);
|
||||
CHECK((r == 0 && d_len == 16));
|
||||
|
||||
@ -207,13 +207,12 @@ TEST_CASE("compress_zstd") {
|
||||
#endif // DEBUG
|
||||
|
||||
TEST_CASE("upx_zstd_decompress") {
|
||||
typedef const upx_byte C;
|
||||
C *c_data;
|
||||
upx_byte d_buf[32];
|
||||
const byte *c_data;
|
||||
byte d_buf[32];
|
||||
unsigned d_len;
|
||||
int r;
|
||||
|
||||
c_data = (C *) "\x28\xb5\x2f\xfd\x20\x20\x3d\x00\x00\x08\xff\x01\x00\x34\x4e\x08";
|
||||
c_data = (const byte *) "\x28\xb5\x2f\xfd\x20\x20\x3d\x00\x00\x08\xff\x01\x00\x34\x4e\x08";
|
||||
d_len = 32;
|
||||
r = upx_zstd_decompress(c_data, 16, d_buf, &d_len, M_ZSTD, nullptr);
|
||||
CHECK((r == 0 && d_len == 32));
|
||||
|
||||
144
src/conf.h
144
src/conf.h
@ -100,6 +100,7 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char
|
||||
# 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
|
||||
@ -124,22 +125,30 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#if __STDC_NO_ATOMICS__ || 1
|
||||
// UPX currently does not use multithreading
|
||||
#define upx_std_atomic(Type) Type
|
||||
//#define upx_std_atomic(Type) typename std::add_volatile<Type>::type
|
||||
#define upx_std_once_flag upx_std_atomic(size_t)
|
||||
template <class NoexceptCallable>
|
||||
inline void upx_std_call_once(upx_std_once_flag &flag, NoexceptCallable &&f) {
|
||||
if (__acc_unlikely(!flag)) { flag = 1; f(); }
|
||||
}
|
||||
#else
|
||||
|
||||
// multithreading (UPX currently does not use multithreading)
|
||||
#ifndef WITH_THREADS
|
||||
# define WITH_THREADS 0
|
||||
#endif
|
||||
#if __STDC_NO_ATOMICS__
|
||||
# undef WITH_THREADS
|
||||
#endif
|
||||
#if (WITH_THREADS)
|
||||
#define upx_thread_local thread_local
|
||||
#include <atomic>
|
||||
#define upx_std_atomic(Type) std::atomic<Type>
|
||||
#include <mutex>
|
||||
#define upx_std_once_flag std::once_flag
|
||||
#define upx_std_call_once std::call_once
|
||||
#endif
|
||||
#else
|
||||
#define upx_thread_local /*empty*/
|
||||
#define upx_std_atomic(Type) Type
|
||||
#define upx_std_once_flag upx_std_atomic(size_t)
|
||||
template <class NoexceptCallable>
|
||||
inline void upx_std_call_once(upx_std_once_flag &flag, NoexceptCallable &&f) {
|
||||
if (__acc_unlikely(!flag)) { flag = 1; f(); }
|
||||
}
|
||||
#endif // WITH_THREADS
|
||||
|
||||
// C++ submodule headers
|
||||
#include <doctest/doctest/parts/doctest_fwd.h>
|
||||
@ -166,16 +175,39 @@ inline void upx_std_call_once(upx_std_once_flag &flag, NoexceptCallable &&f) {
|
||||
|
||||
// <type_traits> C++20 std::is_bounded_array
|
||||
template <class T>
|
||||
struct std_is_bounded_array : public std::false_type {};
|
||||
struct upx_std_is_bounded_array : public std::false_type {};
|
||||
template <class T, size_t N>
|
||||
struct std_is_bounded_array<T[N]> : public std::true_type {};
|
||||
struct upx_std_is_bounded_array<T[N]> : public std::true_type {};
|
||||
template <class T>
|
||||
inline constexpr bool upx_std_is_bounded_array_v = upx_std_is_bounded_array<T>::value;
|
||||
|
||||
// see bele.h
|
||||
template <class T>
|
||||
struct upx_is_integral : public std::is_integral<T> {};
|
||||
template <class T>
|
||||
inline constexpr bool upx_is_integral_v = upx_is_integral<T>::value;
|
||||
|
||||
#if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__)
|
||||
// horrible hack for broken compiler
|
||||
#define upx_fake_alignas_1 __attribute__((__aligned__(1),__packed__))
|
||||
#define upx_fake_alignas_16 __attribute__((__aligned__(2))) // object file maximum 2 ???
|
||||
#define upx_fake_alignas__(a) upx_fake_alignas_ ## a
|
||||
#define alignas(x) upx_fake_alignas__(x)
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
// core
|
||||
**************************************************************************/
|
||||
|
||||
// intergral types
|
||||
// protect against integer overflows and malicious header fields
|
||||
// see C 11 standard, Annex K
|
||||
typedef size_t upx_rsize_t;
|
||||
#define UPX_RSIZE_MAX UPX_RSIZE_MAX_MEM
|
||||
#define UPX_RSIZE_MAX_MEM (768 * 1024 * 1024) // DO NOT CHANGE !!!
|
||||
#define UPX_RSIZE_MAX_STR (256 * 1024)
|
||||
|
||||
// integral types
|
||||
typedef acc_int8_t upx_int8_t;
|
||||
typedef acc_uint8_t upx_uint8_t;
|
||||
typedef acc_int16_t upx_int16_t;
|
||||
@ -186,16 +218,17 @@ typedef acc_int64_t upx_int64_t;
|
||||
typedef acc_uint64_t upx_uint64_t;
|
||||
typedef acc_uintptr_t upx_uintptr_t;
|
||||
|
||||
// convention: use "byte" when dealing with data; use "char/uchar" when dealing
|
||||
// with strings; use "upx_uint8_t" when dealing with small integers
|
||||
typedef unsigned char byte;
|
||||
#define upx_byte byte
|
||||
#define upx_bytep byte *
|
||||
|
||||
// protect against integer overflows and malicious header fields
|
||||
// see C 11 standard, Annex K
|
||||
typedef size_t upx_rsize_t;
|
||||
#define UPX_RSIZE_MAX UPX_RSIZE_MAX_MEM
|
||||
#define UPX_RSIZE_MAX_MEM (768 * 1024 * 1024) // DO NOT CHANGE !!!
|
||||
#define UPX_RSIZE_MAX_STR (1024 * 1024)
|
||||
typedef unsigned char uchar;
|
||||
// use "charptr" when dealing with pointer arithmetics
|
||||
#define charptr upx_charptr_unit_type *
|
||||
// upx_charptr_unit_type is some opaque type with sizeof(type) == 1
|
||||
struct alignas(1) upx_charptr_unit_type { char dummy; };
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(upx_charptr_unit_type) == 1)
|
||||
|
||||
// using the system off_t was a bad idea even back in 199x...
|
||||
typedef upx_int64_t upx_off_t;
|
||||
@ -244,8 +277,8 @@ typedef upx_int64_t upx_off_t;
|
||||
#endif
|
||||
#if (ACC_OS_DOS32) && defined(__DJGPP__)
|
||||
# undef sopen
|
||||
# undef __unix__
|
||||
# undef __unix
|
||||
# undef __unix__
|
||||
#endif
|
||||
|
||||
#ifndef STDIN_FILENO
|
||||
@ -304,7 +337,7 @@ typedef upx_int64_t upx_off_t;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// avoid warnings about shadowing global functions
|
||||
// avoid warnings about shadowing global symbols
|
||||
#undef _base
|
||||
#undef basename
|
||||
#undef index
|
||||
@ -391,14 +424,6 @@ inline void NO_fprintf(FILE *, const char *, ...) {}
|
||||
#define __packed_struct(s) struct alignas(1) s {
|
||||
#define __packed_struct_end() };
|
||||
|
||||
#if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__)
|
||||
// horrible hack for broken compiler
|
||||
#define upx_fake_alignas_1 __attribute__((__aligned__(1),__packed__))
|
||||
#define upx_fake_alignas_16 __attribute__((__aligned__(2))) // object file maximum 2 ???
|
||||
#define upx_fake_alignas__(a) upx_fake_alignas_ ## a
|
||||
#define alignas(x) upx_fake_alignas__(x)
|
||||
#endif
|
||||
|
||||
#define COMPILE_TIME_ASSERT_ALIGNOF_USING_SIZEOF__(a,b) { \
|
||||
typedef a acc_tmp_a_t; typedef b acc_tmp_b_t; \
|
||||
struct alignas(1) acc_tmp_t { acc_tmp_b_t x; acc_tmp_a_t y; acc_tmp_b_t z; }; \
|
||||
@ -426,15 +451,13 @@ inline const T& UPX_MAX(const T& a, const T& b) { if (a < b) return b; return a;
|
||||
template <class T>
|
||||
inline const T& UPX_MIN(const T& a, const T& b) { if (a < b) return a; return b; }
|
||||
|
||||
template <size_t TypeSize>
|
||||
struct USizeOfTypeImpl {
|
||||
static forceinline constexpr unsigned value() {
|
||||
COMPILE_TIME_ASSERT(TypeSize >= 1 && TypeSize <= 64 * 1024) // arbitrary limit
|
||||
return ACC_ICONV(unsigned, TypeSize);
|
||||
}
|
||||
template <size_t Size>
|
||||
struct UnsignedSizeOf {
|
||||
static_assert(Size >= 1 && Size <= UPX_RSIZE_MAX_MEM);
|
||||
static constexpr unsigned value = unsigned(Size);
|
||||
};
|
||||
#define usizeof(type) (USizeOfTypeImpl<sizeof(type)>::value())
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(int) == 4)
|
||||
#define usizeof(expr) (UnsignedSizeOf<sizeof(expr)>::value)
|
||||
ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(int) == sizeof(int))
|
||||
|
||||
// An Array allocates memory on the heap, and automatically
|
||||
// gets destructed when leaving scope or on exceptions.
|
||||
@ -442,16 +465,16 @@ ACC_COMPILE_TIME_ASSERT_HEADER(usizeof(int) == 4)
|
||||
MemBuffer var ## _membuf(mem_size(sizeof(type), size)); \
|
||||
type * const var = ACC_STATIC_CAST(type *, var ## _membuf.getVoidPtr())
|
||||
|
||||
#define ByteArray(var, size) Array(unsigned char, var, size)
|
||||
#define ByteArray(var, size) Array(byte, var, size)
|
||||
|
||||
|
||||
class noncopyable
|
||||
{
|
||||
protected:
|
||||
inline noncopyable() {}
|
||||
inline ~noncopyable() {}
|
||||
inline noncopyable() noexcept {}
|
||||
inline ~noncopyable() noexcept {}
|
||||
private:
|
||||
noncopyable(const noncopyable &) DELETED_FUNCTION; // copy constuctor
|
||||
noncopyable(const noncopyable &) DELETED_FUNCTION; // copy constructor
|
||||
noncopyable& operator=(const noncopyable &) DELETED_FUNCTION; // copy assignment
|
||||
noncopyable(noncopyable &&) DELETED_FUNCTION; // move constructor
|
||||
noncopyable& operator=(noncopyable &&) DELETED_FUNCTION; // move assignment
|
||||
@ -466,7 +489,7 @@ constexpr bool string_eq(const char *a, const char *b) {
|
||||
return *a == *b && (*a == '\0' || string_eq(a + 1, b + 1));
|
||||
}
|
||||
constexpr bool string_lt(const char *a, const char *b) {
|
||||
return (unsigned char)*a < (unsigned char)*b || (*a != '\0' && *a == *b && string_lt(a + 1, b + 1));
|
||||
return (uchar)*a < (uchar)*b || (*a != '\0' && *a == *b && string_lt(a + 1, b + 1));
|
||||
}
|
||||
constexpr bool string_ne(const char *a, const char *b) {
|
||||
return !string_eq(a, b);
|
||||
@ -644,7 +667,7 @@ struct upx_callback_t
|
||||
upx_progress_func_t nprogress;
|
||||
void *user;
|
||||
|
||||
void reset() { memset(this, 0, sizeof(*this)); }
|
||||
void reset() noexcept { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
|
||||
@ -670,7 +693,7 @@ struct OptVar
|
||||
assertValue(v);
|
||||
}
|
||||
|
||||
OptVar() : v(default_value), is_set(false) { }
|
||||
OptVar() noexcept : v(default_value), is_set(false) { }
|
||||
OptVar& operator= (const T &other) {
|
||||
assertValue(other);
|
||||
v = other;
|
||||
@ -678,8 +701,8 @@ struct OptVar
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset() { v = default_value; is_set = false; }
|
||||
operator T () const { return v; }
|
||||
void reset() noexcept { v = default_value; is_set = false; }
|
||||
operator T () const noexcept { return v; }
|
||||
|
||||
T v;
|
||||
bool is_set;
|
||||
@ -818,26 +841,16 @@ struct upx_compress_result_t
|
||||
// globals
|
||||
**************************************************************************/
|
||||
|
||||
#include "util/snprintf.h" // must get included first!
|
||||
#include "options.h"
|
||||
#include "except.h"
|
||||
#include "bele.h"
|
||||
#include "console/console.h"
|
||||
#include "util/util.h"
|
||||
|
||||
// classes
|
||||
class ElfLinker;
|
||||
typedef ElfLinker Linker;
|
||||
class Throwable;
|
||||
|
||||
// util/membuffer.h
|
||||
class MemBuffer;
|
||||
void *membuffer_get_void_ptr(MemBuffer &mb);
|
||||
unsigned membuffer_get_size(MemBuffer &mb);
|
||||
|
||||
// xspan
|
||||
#include "util/raw_bytes.h"
|
||||
#include "util/xspan.h"
|
||||
|
||||
// util/dt_check.cpp
|
||||
void upx_compiler_sanity_check();
|
||||
int upx_doctest_check();
|
||||
@ -870,7 +883,7 @@ int do_files(int i, int argc, char *argv[]);
|
||||
|
||||
// help.cpp
|
||||
extern const char gitrev[];
|
||||
void show_head();
|
||||
void show_header();
|
||||
void show_help(int verbose=0);
|
||||
void show_license();
|
||||
void show_usage();
|
||||
@ -898,6 +911,17 @@ int upx_test_overlap ( const upx_bytep buf,
|
||||
const upx_compress_result_t *cresult );
|
||||
|
||||
|
||||
#include "util/snprintf.h" // must get included first!
|
||||
#include "options.h"
|
||||
#include "except.h"
|
||||
#include "bele.h"
|
||||
#include "console/console.h"
|
||||
#include "util/util.h"
|
||||
// xspan
|
||||
#include "util/raw_bytes.h"
|
||||
#include "util/xspan.h"
|
||||
|
||||
|
||||
#if (ACC_OS_CYGWIN || ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_EMX || ACC_OS_OS2 || ACC_OS_OS216 || ACC_OS_WIN16 || ACC_OS_WIN32 || ACC_OS_WIN64)
|
||||
# if defined(INVALID_HANDLE_VALUE) || defined(MAKEWORD) || defined(RT_CURSOR)
|
||||
# error "something pulled in <windows.h>"
|
||||
|
||||
11
src/file.cpp
11
src/file.cpp
@ -269,6 +269,17 @@ void OutputFile::write(SPAN_0(const void) buf, int len) {
|
||||
if (l != len)
|
||||
throwIOException("write error", errno);
|
||||
bytes_written += len;
|
||||
#if TESTING && 0
|
||||
static upx_std_atomic(bool) dumping;
|
||||
if (!dumping) {
|
||||
dumping = true;
|
||||
char fn[64];
|
||||
static int part = 0;
|
||||
snprintf(fn, sizeof(fn), "upx-dump-%04d.data", part++);
|
||||
OutputFile::dump(fn, buf, len);
|
||||
dumping = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
upx_off_t OutputFile::st_size() const {
|
||||
|
||||
216
src/help.cpp
216
src/help.cpp
@ -25,36 +25,33 @@
|
||||
<markus@oberhumer.com> <ezerotven+github@gmail.com>
|
||||
*/
|
||||
|
||||
|
||||
#include "conf.h"
|
||||
#include "packmast.h"
|
||||
#include "packer.h"
|
||||
#include "compress/compress.h" // upx_ucl_version_string()
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
// header
|
||||
**************************************************************************/
|
||||
|
||||
static bool head_done = 0;
|
||||
|
||||
// also see UPX_CONFIG_DISABLE_GITREV in CMakeLists.txt
|
||||
#if defined(UPX_VERSION_GITREV)
|
||||
const char gitrev[] = UPX_VERSION_GITREV;
|
||||
#else
|
||||
const char gitrev[1] = { 0 };
|
||||
const char gitrev[1] = {0};
|
||||
#endif
|
||||
|
||||
void show_head(void)
|
||||
{
|
||||
void show_header(void) {
|
||||
FILE *f = con_term;
|
||||
int fg;
|
||||
|
||||
if (head_done)
|
||||
static bool header_done;
|
||||
if (header_done)
|
||||
return;
|
||||
head_done = 1;
|
||||
header_done = true;
|
||||
|
||||
fg = con_fg(f,FG_GREEN);
|
||||
fg = con_fg(f, FG_GREEN);
|
||||
// clang-format off
|
||||
con_fprintf(f,
|
||||
" Ultimate Packer for eXecutables\n"
|
||||
" Copyright (C) 1996 - " UPX_VERSION_YEAR "\n"
|
||||
@ -71,22 +68,19 @@ void show_head(void)
|
||||
UPX_VERSION_STRING,
|
||||
#endif
|
||||
UPX_VERSION_DATE);
|
||||
fg = con_fg(f,fg);
|
||||
#undef V
|
||||
|
||||
// clang-format on
|
||||
fg = con_fg(f, fg);
|
||||
UNUSED(fg);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
// usage
|
||||
**************************************************************************/
|
||||
|
||||
void show_usage(void)
|
||||
{
|
||||
void show_usage(void) {
|
||||
FILE *f = con_term;
|
||||
|
||||
con_fprintf(f,"Usage: %s [-123456789dlthVL] [-qvfk] [-o file] %sfile..\n", progname,
|
||||
con_fprintf(f, "Usage: %s [-123456789dlthVL] [-qvfk] [-o file] %sfile..\n", progname,
|
||||
#if (ACC_OS_DOS32) && defined(__DJGPP__)
|
||||
"[@]");
|
||||
#else
|
||||
@ -94,34 +88,30 @@ void show_usage(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
// util
|
||||
**************************************************************************/
|
||||
|
||||
struct PackerNames
|
||||
{
|
||||
namespace {
|
||||
struct PackerNames {
|
||||
struct Entry {
|
||||
const char* fname;
|
||||
const char* sname;
|
||||
const char *fname;
|
||||
const char *sname;
|
||||
};
|
||||
Entry names[64];
|
||||
size_t names_count;
|
||||
const options_t *o;
|
||||
PackerNames() : names_count(0), o(nullptr) { }
|
||||
void add(const Packer *p)
|
||||
{
|
||||
p->assertPacker();
|
||||
const Options *o;
|
||||
PackerNames() : names_count(0), o(nullptr) {}
|
||||
void add(const Packer *p) {
|
||||
assert(names_count < 64);
|
||||
names[names_count].fname = p->getFullName(o);
|
||||
names[names_count].sname = p->getName();
|
||||
names_count++;
|
||||
}
|
||||
static Packer* visit(Packer *p, void *user)
|
||||
{
|
||||
static Packer *visit(Packer *p, void *user) {
|
||||
PackerNames *self = (PackerNames *) user;
|
||||
self->add(p);
|
||||
delete p; p = nullptr;
|
||||
delete p;
|
||||
return nullptr;
|
||||
}
|
||||
static int __acc_cdecl_qsort cmp_fname(const void *a, const void *b) {
|
||||
@ -132,23 +122,20 @@ struct PackerNames
|
||||
}
|
||||
};
|
||||
|
||||
static void show_all_packers(FILE *f, int verbose)
|
||||
{
|
||||
options_t o; o.reset();
|
||||
PackerNames pn; pn.o = &o;
|
||||
static void show_all_packers(FILE *f, int verbose) {
|
||||
Options o;
|
||||
o.reset();
|
||||
PackerNames pn;
|
||||
pn.o = &o;
|
||||
PackMaster::visitAllPackers(PackerNames::visit, nullptr, &o, &pn);
|
||||
qsort(pn.names, pn.names_count, sizeof(PackerNames::Entry), PackerNames::cmp_fname);
|
||||
size_t pos = 0;
|
||||
for (size_t i = 0; i < pn.names_count; ++i)
|
||||
{
|
||||
for (size_t i = 0; i < pn.names_count; ++i) {
|
||||
const char *fn = pn.names[i].fname;
|
||||
const char *sn = pn.names[i].sname;
|
||||
if (verbose > 0)
|
||||
{
|
||||
if (verbose > 0) {
|
||||
con_fprintf(f, " %-36s %s\n", fn, sn);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
size_t fl = strlen(fn);
|
||||
if (pos == 0) {
|
||||
con_fprintf(f, " %s", fn);
|
||||
@ -165,23 +152,23 @@ static void show_all_packers(FILE *f, int verbose)
|
||||
if (verbose <= 0 && pn.names_count)
|
||||
con_fprintf(f, "\n");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
// help
|
||||
**************************************************************************/
|
||||
|
||||
void show_help(int verbose)
|
||||
{
|
||||
void show_help(int verbose) {
|
||||
FILE *f = con_term;
|
||||
int fg;
|
||||
|
||||
show_head();
|
||||
show_header();
|
||||
show_usage();
|
||||
|
||||
fg = con_fg(f,FG_YELLOW);
|
||||
con_fprintf(f,"\nCommands:\n");
|
||||
fg = con_fg(f,fg);
|
||||
// clang-format off
|
||||
fg = con_fg(f, FG_YELLOW);
|
||||
con_fprintf(f, "\nCommands:\n");
|
||||
fg = con_fg(f, fg);
|
||||
con_fprintf(f,
|
||||
" -1 compress faster -9 compress better\n"
|
||||
"%s"
|
||||
@ -191,9 +178,9 @@ void show_help(int verbose)
|
||||
verbose == 0 ? "" : " --best compress best (can be slow for big files)\n",
|
||||
verbose == 0 ? "more" : "this", verbose == 0 ? "" : "\n");
|
||||
|
||||
fg = con_fg(f,FG_YELLOW);
|
||||
con_fprintf(f,"Options:\n");
|
||||
fg = con_fg(f,fg);
|
||||
fg = con_fg(f, FG_YELLOW);
|
||||
con_fprintf(f, "Options:\n");
|
||||
fg = con_fg(f, fg);
|
||||
|
||||
con_fprintf(f,
|
||||
" -q be quiet -v be verbose\n"
|
||||
@ -211,72 +198,72 @@ void show_help(int verbose)
|
||||
|
||||
if (verbose > 0)
|
||||
{
|
||||
fg = con_fg(f,FG_YELLOW);
|
||||
con_fprintf(f,"\nCompression tuning options:\n");
|
||||
fg = con_fg(f,fg);
|
||||
fg = con_fg(f, FG_YELLOW);
|
||||
con_fprintf(f, "\nCompression tuning options:\n");
|
||||
fg = con_fg(f, fg);
|
||||
con_fprintf(f,
|
||||
" --lzma try LZMA [slower but tighter than NRV]\n"
|
||||
" --brute try all available compression methods & filters [slow]\n"
|
||||
" --ultra-brute try even more compression variants [very slow]\n"
|
||||
"\n");
|
||||
fg = con_fg(f,FG_YELLOW);
|
||||
con_fprintf(f,"Backup options:\n");
|
||||
fg = con_fg(f,fg);
|
||||
fg = con_fg(f, FG_YELLOW);
|
||||
con_fprintf(f, "Backup options:\n");
|
||||
fg = con_fg(f, fg);
|
||||
con_fprintf(f,
|
||||
" -k, --backup keep backup files\n"
|
||||
" --no-backup no backup files [default]\n"
|
||||
"\n");
|
||||
fg = con_fg(f,FG_YELLOW);
|
||||
con_fprintf(f,"Overlay options:\n");
|
||||
fg = con_fg(f,fg);
|
||||
fg = con_fg(f, FG_YELLOW);
|
||||
con_fprintf(f, "Overlay options:\n");
|
||||
fg = con_fg(f, fg);
|
||||
con_fprintf(f,
|
||||
" --overlay=copy copy any extra data attached to the file [default]\n"
|
||||
" --overlay=strip strip any extra data attached to the file [DANGEROUS]\n"
|
||||
" --overlay=skip don't compress a file with an overlay\n"
|
||||
"\n");
|
||||
fg = con_fg(f,FG_YELLOW);
|
||||
con_fprintf(f,"Options for djgpp2/coff:\n");
|
||||
fg = con_fg(f,fg);
|
||||
fg = con_fg(f, FG_YELLOW);
|
||||
con_fprintf(f, "Options for djgpp2/coff:\n");
|
||||
fg = con_fg(f, fg);
|
||||
con_fprintf(f,
|
||||
" --coff produce COFF output [default: EXE]\n"
|
||||
"\n");
|
||||
fg = con_fg(f,FG_YELLOW);
|
||||
con_fprintf(f,"Options for dos/com:\n");
|
||||
fg = con_fg(f,fg);
|
||||
fg = con_fg(f, FG_YELLOW);
|
||||
con_fprintf(f, "Options for dos/com:\n");
|
||||
fg = con_fg(f, fg);
|
||||
con_fprintf(f,
|
||||
" --8086 make compressed com work on any 8086\n"
|
||||
"\n");
|
||||
fg = con_fg(f,FG_YELLOW);
|
||||
con_fprintf(f,"Options for dos/exe:\n");
|
||||
fg = con_fg(f,fg);
|
||||
fg = con_fg(f, FG_YELLOW);
|
||||
con_fprintf(f, "Options for dos/exe:\n");
|
||||
fg = con_fg(f, fg);
|
||||
con_fprintf(f,
|
||||
" --8086 make compressed exe work on any 8086\n"
|
||||
" --no-reloc put no relocations in to the exe header\n"
|
||||
"\n");
|
||||
fg = con_fg(f,FG_YELLOW);
|
||||
con_fprintf(f,"Options for dos/sys:\n");
|
||||
fg = con_fg(f,fg);
|
||||
fg = con_fg(f, FG_YELLOW);
|
||||
con_fprintf(f, "Options for dos/sys:\n");
|
||||
fg = con_fg(f, fg);
|
||||
con_fprintf(f,
|
||||
" --8086 make compressed sys work on any 8086\n"
|
||||
"\n");
|
||||
fg = con_fg(f,FG_YELLOW);
|
||||
con_fprintf(f,"Options for ps1/exe:\n");
|
||||
fg = con_fg(f,fg);
|
||||
fg = con_fg(f, FG_YELLOW);
|
||||
con_fprintf(f, "Options for ps1/exe:\n");
|
||||
fg = con_fg(f, fg);
|
||||
con_fprintf(f,
|
||||
" --8-bit uses 8 bit size compression [default: 32 bit]\n"
|
||||
" --8mib-ram 8 megabyte memory limit [default: 2 MiB]\n"
|
||||
" --boot-only disables client/host transfer compatibility\n"
|
||||
" --no-align don't align to 2048 bytes [enables: --console-run]\n"
|
||||
"\n");
|
||||
fg = con_fg(f,FG_YELLOW);
|
||||
con_fprintf(f,"Options for watcom/le:\n");
|
||||
fg = con_fg(f,fg);
|
||||
fg = con_fg(f, FG_YELLOW);
|
||||
con_fprintf(f, "Options for watcom/le:\n");
|
||||
fg = con_fg(f, fg);
|
||||
con_fprintf(f,
|
||||
" --le produce LE output [default: EXE]\n"
|
||||
"\n");
|
||||
fg = con_fg(f,FG_YELLOW);
|
||||
con_fprintf(f,"Options for win32/pe, win64/pe & rtm32/pe:\n");
|
||||
fg = con_fg(f,fg);
|
||||
fg = con_fg(f, FG_YELLOW);
|
||||
con_fprintf(f, "Options for win32/pe, win64/pe & rtm32/pe:\n");
|
||||
fg = con_fg(f, fg);
|
||||
con_fprintf(f,
|
||||
" --compress-exports=0 do not compress the export section\n"
|
||||
" --compress-exports=1 compress the export section [default]\n"
|
||||
@ -289,35 +276,32 @@ void show_help(int verbose)
|
||||
" --strip-relocs=0 do not strip relocations\n"
|
||||
" --strip-relocs=1 strip relocations [default]\n"
|
||||
"\n");
|
||||
fg = con_fg(f,FG_YELLOW);
|
||||
con_fprintf(f,"Options for linux/elf:\n");
|
||||
fg = con_fg(f,fg);
|
||||
fg = con_fg(f, FG_YELLOW);
|
||||
con_fprintf(f, "Options for linux/elf:\n");
|
||||
fg = con_fg(f, fg);
|
||||
con_fprintf(f,
|
||||
" --preserve-build-id copy .gnu.note.build-id to compressed output\n"
|
||||
"\n");
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
con_fprintf(f, "file.. executables to (de)compress\n");
|
||||
|
||||
if (verbose > 0)
|
||||
{
|
||||
fg = con_fg(f,FG_YELLOW);
|
||||
con_fprintf(f,"\nThis version supports:\n");
|
||||
fg = con_fg(f,fg);
|
||||
if (verbose > 0) {
|
||||
fg = con_fg(f, FG_YELLOW);
|
||||
con_fprintf(f, "\nThis version supports:\n");
|
||||
fg = con_fg(f, fg);
|
||||
show_all_packers(f, verbose);
|
||||
}
|
||||
else
|
||||
{
|
||||
con_fprintf(f,"\nType '%s --help' for more detailed help.\n", progname);
|
||||
} else {
|
||||
con_fprintf(f, "\nType '%s --help' for more detailed help.\n", progname);
|
||||
}
|
||||
|
||||
con_fprintf(f,"\nUPX comes with ABSOLUTELY NO WARRANTY; for details visit https://upx.github.io\n"
|
||||
// "\nUPX comes with ABSOLUTELY NO WARRANTY; for details type 'upx -L'.\n"
|
||||
"");
|
||||
con_fprintf(f, "\nUPX comes with ABSOLUTELY NO WARRANTY; "
|
||||
"for details visit https://upx.github.io\n");
|
||||
|
||||
#if DEBUG || TESTING
|
||||
fg = con_fg(f,FG_RED);
|
||||
con_fprintf(f,"\nWARNING: this version is compiled with"
|
||||
fg = con_fg(f, FG_RED);
|
||||
con_fprintf(f, "\nWARNING: this version is compiled with"
|
||||
#if DEBUG
|
||||
" -DDEBUG"
|
||||
#endif
|
||||
@ -325,23 +309,22 @@ void show_help(int verbose)
|
||||
" -DTESTING"
|
||||
#endif
|
||||
"\n");
|
||||
fg = con_fg(f,fg);
|
||||
fg = con_fg(f, fg);
|
||||
#endif
|
||||
|
||||
UNUSED(fg);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
// license
|
||||
**************************************************************************/
|
||||
|
||||
void show_license(void)
|
||||
{
|
||||
void show_license(void) {
|
||||
FILE *f = con_term;
|
||||
|
||||
show_head();
|
||||
show_header();
|
||||
|
||||
// clang-format off
|
||||
con_fprintf(f,
|
||||
" This program may be used freely, and you are welcome to\n"
|
||||
" redistribute it under certain conditions.\n"
|
||||
@ -356,29 +339,27 @@ void show_license(void)
|
||||
" If not, visit one of the following pages:\n"
|
||||
"\n"
|
||||
);
|
||||
int fg = con_fg(f,FG_CYAN);
|
||||
int fg = con_fg(f, FG_CYAN);
|
||||
con_fprintf(f,
|
||||
" https://upx.github.io\n"
|
||||
" https://www.oberhumer.com/opensource/upx/\n"
|
||||
);
|
||||
(void)con_fg(f,FG_ORANGE);
|
||||
(void) con_fg(f, FG_ORANGE);
|
||||
con_fprintf(f,
|
||||
"\n"
|
||||
" Markus F.X.J. Oberhumer Laszlo Molnar\n"
|
||||
" <markus@oberhumer.com> <ezerotven+github@gmail.com>\n"
|
||||
);
|
||||
fg = con_fg(f,fg);
|
||||
|
||||
// clang-format on
|
||||
fg = con_fg(f, fg);
|
||||
UNUSED(fg);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
// version
|
||||
**************************************************************************/
|
||||
|
||||
void show_version(bool one_line)
|
||||
{
|
||||
void show_version(bool one_line) {
|
||||
FILE *fp = stdout;
|
||||
const char *v;
|
||||
|
||||
@ -391,6 +372,7 @@ void show_version(bool one_line)
|
||||
#endif
|
||||
if (one_line)
|
||||
return;
|
||||
|
||||
#if (WITH_NRV)
|
||||
v = upx_nrv_version_string();
|
||||
if (v != nullptr && v[0])
|
||||
@ -419,6 +401,7 @@ void show_version(bool one_line)
|
||||
#if !defined(DOCTEST_CONFIG_DISABLE)
|
||||
fprintf(fp, "doctest C++ testing framework version %s\n", DOCTEST_VERSION_STR);
|
||||
#endif
|
||||
// clang-format off
|
||||
fprintf(fp, "Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer\n");
|
||||
fprintf(fp, "Copyright (C) 1996-2023 Laszlo Molnar\n");
|
||||
fprintf(fp, "Copyright (C) 2000-2023 John F. Reiser\n");
|
||||
@ -437,6 +420,7 @@ void show_version(bool one_line)
|
||||
fprintf(fp, "Copyright (C) 2016" "-2021 Viktor Kirilov\n");
|
||||
#endif
|
||||
fprintf(fp, "UPX comes with ABSOLUTELY NO WARRANTY; for details type '%s -L'.\n", progname);
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
#include "conf.h"
|
||||
#include "linker.h"
|
||||
|
||||
static unsigned hex(unsigned char c) { return (c & 0xf) + (c > '9' ? 9 : 0); }
|
||||
static unsigned hex(uchar c) { return (c & 0xf) + (c > '9' ? 9 : 0); }
|
||||
|
||||
static bool update_capacity(unsigned size, unsigned *capacity) {
|
||||
if (size < *capacity)
|
||||
@ -67,7 +67,7 @@ ElfLinker::Section::Section(const char *n, const void *i, unsigned s, unsigned a
|
||||
((char *) input)[s] = 0;
|
||||
}
|
||||
|
||||
ElfLinker::Section::~Section() {
|
||||
ElfLinker::Section::~Section() noexcept {
|
||||
free(name);
|
||||
free(input);
|
||||
}
|
||||
@ -83,7 +83,7 @@ ElfLinker::Symbol::Symbol(const char *n, Section *s, upx_uint64_t o)
|
||||
assert(section != nullptr);
|
||||
}
|
||||
|
||||
ElfLinker::Symbol::~Symbol() { free(name); }
|
||||
ElfLinker::Symbol::~Symbol() noexcept { free(name); }
|
||||
|
||||
/*************************************************************************
|
||||
// Relocation
|
||||
@ -105,7 +105,7 @@ ElfLinker::ElfLinker()
|
||||
nsections_capacity(0), nsymbols(0), nsymbols_capacity(0), nrelocations(0),
|
||||
nrelocations_capacity(0), reloc_done(false) {}
|
||||
|
||||
ElfLinker::~ElfLinker() {
|
||||
ElfLinker::~ElfLinker() noexcept {
|
||||
delete[] input;
|
||||
delete[] output;
|
||||
|
||||
@ -548,7 +548,7 @@ upx_uint64_t ElfLinker::getSymbolOffset(const char *name) const {
|
||||
return symbol->section->offset + symbol->offset;
|
||||
}
|
||||
|
||||
void ElfLinker::alignWithByte(unsigned len, unsigned char b) {
|
||||
void ElfLinker::alignWithByte(unsigned len, byte b) {
|
||||
memset(output + outputlen, b, len);
|
||||
outputlen += len;
|
||||
}
|
||||
@ -559,7 +559,7 @@ void ElfLinker::relocate1(const Relocation *rel, byte *, upx_uint64_t, const cha
|
||||
|
||||
/*************************************************************************
|
||||
// ElfLinker arch subclasses
|
||||
// FIXME: add more displacment overflow checks
|
||||
// FIXME: add more displacement overflow checks
|
||||
// FIXME: add support for our special "ignore_reloc_overflow" section
|
||||
**************************************************************************/
|
||||
|
||||
@ -802,12 +802,12 @@ void ElfLinkerPpc32::relocate1(const Relocation *rel, byte *location, upx_uint64
|
||||
if (strcmp(type, "24") == 0) {
|
||||
if (3 & value)
|
||||
internal_error("unaligned word diplacement");
|
||||
// FIXME: displacment overflow?
|
||||
// FIXME: displacement overflow?
|
||||
set_be32(location, (0xfc000003 & get_be32(location)) + (0x03fffffc & value));
|
||||
} else if (strcmp(type, "14") == 0) {
|
||||
if (3 & value)
|
||||
internal_error("unaligned word diplacement");
|
||||
// FIXME: displacment overflow?
|
||||
// FIXME: displacement overflow?
|
||||
set_be32(location, (0xffff0003 & get_be32(location)) + (0x0000fffc & value));
|
||||
} else
|
||||
super::relocate1(rel, location, value, type);
|
||||
|
||||
@ -77,7 +77,7 @@ protected:
|
||||
|
||||
public:
|
||||
ElfLinker();
|
||||
virtual ~ElfLinker();
|
||||
virtual ~ElfLinker() noexcept;
|
||||
|
||||
void init(const void *pdata, int plen, unsigned pxtra = 0);
|
||||
// virtual void setLoaderAlignOffset(int phase);
|
||||
@ -98,7 +98,7 @@ public:
|
||||
void dumpSymbol(const Symbol *, unsigned flags, FILE *fp) const;
|
||||
void dumpSymbols(unsigned flags = 0, FILE *fp = nullptr) const;
|
||||
|
||||
void alignWithByte(unsigned len, unsigned char b);
|
||||
void alignWithByte(unsigned len, byte b);
|
||||
virtual void alignCode(unsigned len) { alignWithByte(len, 0); }
|
||||
virtual void alignData(unsigned len) { alignWithByte(len, 0); }
|
||||
|
||||
@ -133,7 +133,7 @@ struct ElfLinker::Section : private noncopyable {
|
||||
Section *next = nullptr;
|
||||
|
||||
Section(const char *n, const void *i, unsigned s, unsigned a = 0);
|
||||
~Section();
|
||||
~Section() noexcept;
|
||||
};
|
||||
|
||||
struct ElfLinker::Symbol : private noncopyable {
|
||||
@ -142,7 +142,7 @@ struct ElfLinker::Symbol : private noncopyable {
|
||||
upx_uint64_t offset = 0;
|
||||
|
||||
Symbol(const char *n, Section *s, upx_uint64_t o);
|
||||
~Symbol();
|
||||
~Symbol() noexcept;
|
||||
};
|
||||
|
||||
struct ElfLinker::Relocation : private noncopyable {
|
||||
@ -153,6 +153,7 @@ struct ElfLinker::Relocation : private noncopyable {
|
||||
upx_uint64_t add; // used in .rela relocations
|
||||
|
||||
Relocation(const Section *s, unsigned o, const char *t, const Symbol *v, upx_uint64_t a);
|
||||
~Relocation() noexcept {}
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
|
||||
@ -626,7 +626,7 @@ static int do_option(int optc, const char *arg) {
|
||||
opt->backup = 1;
|
||||
break;
|
||||
case 541:
|
||||
if (opt->backup != 1) // do not overide '--backup'
|
||||
if (opt->backup != 1) // do not override '--backup'
|
||||
opt->backup = 0;
|
||||
break;
|
||||
// overlay
|
||||
@ -974,11 +974,10 @@ int main_get_options(int argc, char **argv) {
|
||||
int optc, longind;
|
||||
char shortopts[256];
|
||||
|
||||
prepare_shortopts(shortopts, "123456789hH?V", longopts),
|
||||
prepare_shortopts(shortopts, "123456789hH?V", longopts);
|
||||
acc_getopt_init(&mfx_getopt, 1, argc, argv);
|
||||
mfx_getopt.progname = progname;
|
||||
mfx_getopt.opterr = handle_opterr;
|
||||
opt->o_unix.osabi0 = Elf32_Ehdr::ELFOSABI_LINUX;
|
||||
while ((optc = acc_getopt(&mfx_getopt, shortopts, longopts, &longind)) >= 0) {
|
||||
if (do_option(optc, argv[mfx_optind - 1]) != 0)
|
||||
e_usage();
|
||||
@ -1088,7 +1087,7 @@ void main_get_envoptions() {
|
||||
|
||||
/* alloc temp argv */
|
||||
if (targc > 1)
|
||||
targv = (const char **) calloc(targc + 1, sizeof(char *));
|
||||
targv = (const char **) upx_calloc(targc + 1, sizeof(char *));
|
||||
if (targv == nullptr) {
|
||||
free(env);
|
||||
return;
|
||||
@ -1188,7 +1187,7 @@ int upx_main(int argc, char *argv[]) {
|
||||
char *p;
|
||||
bool allupper = true;
|
||||
for (p = prog; *p; p++)
|
||||
if (islower((unsigned char) *p))
|
||||
if (islower((uchar) *p))
|
||||
allupper = false;
|
||||
if (allupper)
|
||||
fn_strlwr(prog);
|
||||
|
||||
@ -27,15 +27,19 @@
|
||||
|
||||
#include "conf.h"
|
||||
|
||||
static options_t global_options;
|
||||
options_t *opt = &global_options; // also see class PackMaster
|
||||
static Options global_options;
|
||||
Options *opt = &global_options; // also see class PackMaster
|
||||
|
||||
#if WITH_THREADS
|
||||
std::mutex opt_lock_mutex;
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
// reset
|
||||
**************************************************************************/
|
||||
|
||||
void options_t::reset() {
|
||||
options_t *o = this;
|
||||
void Options::reset() {
|
||||
Options *const o = this;
|
||||
mem_clear(o, sizeof(*o));
|
||||
o->crp.reset();
|
||||
|
||||
@ -65,7 +69,7 @@ void options_t::reset() {
|
||||
o->win32_pe.compress_exports = 1;
|
||||
o->win32_pe.compress_icons = 2;
|
||||
o->win32_pe.compress_resources = -1;
|
||||
for (unsigned i = 0; i < TABLESIZE(o->win32_pe.compress_rt); i++)
|
||||
for (size_t i = 0; i < TABLESIZE(o->win32_pe.compress_rt); i++)
|
||||
o->win32_pe.compress_rt[i] = -1;
|
||||
o->win32_pe.compress_rt[24] = false; // 24 == RT_MANIFEST
|
||||
o->win32_pe.strip_relocs = -1;
|
||||
@ -76,9 +80,13 @@ void options_t::reset() {
|
||||
// doctest checks
|
||||
**************************************************************************/
|
||||
|
||||
TEST_CASE("options_t::reset") {
|
||||
options_t local_options;
|
||||
options_t *o = &local_options;
|
||||
TEST_CASE("Options::reset") {
|
||||
COMPILE_TIME_ASSERT(std::is_standard_layout<Options>::value)
|
||||
COMPILE_TIME_ASSERT(std::is_nothrow_default_constructible<Options>::value)
|
||||
COMPILE_TIME_ASSERT(std::is_trivially_copyable<Options>::value)
|
||||
|
||||
Options local_options;
|
||||
Options *o = &local_options;
|
||||
o->reset();
|
||||
CHECK(o->o_unix.osabi0 == 3);
|
||||
}
|
||||
@ -89,8 +97,11 @@ static inline void test_options(const char *(&a)[N]) {
|
||||
}
|
||||
|
||||
TEST_CASE("getopt") {
|
||||
options_t *const saved_opt = opt;
|
||||
options_t local_options;
|
||||
#if WITH_THREADS
|
||||
std::lock_guard<std::mutex> lock(opt_lock_mutex);
|
||||
#endif
|
||||
Options *const saved_opt = opt;
|
||||
Options local_options;
|
||||
opt = &local_options;
|
||||
opt->reset();
|
||||
opt->debug.getopt_throw_instead_of_exit = true;
|
||||
|
||||
@ -29,6 +29,14 @@
|
||||
#ifndef UPX_OPTIONS_H__
|
||||
#define UPX_OPTIONS_H__ 1
|
||||
|
||||
struct Options;
|
||||
extern Options *opt;
|
||||
#define options_t Options // old name
|
||||
|
||||
#if WITH_THREADS
|
||||
extern std::mutex opt_lock_mutex;
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
// globals
|
||||
**************************************************************************/
|
||||
@ -46,7 +54,7 @@ enum {
|
||||
CMD_VERSION,
|
||||
};
|
||||
|
||||
struct options_t final {
|
||||
struct Options final {
|
||||
int cmd;
|
||||
|
||||
// compression options
|
||||
@ -164,8 +172,6 @@ struct options_t final {
|
||||
void reset();
|
||||
};
|
||||
|
||||
extern struct options_t *opt;
|
||||
|
||||
#endif /* already included */
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
|
||||
@ -41,7 +41,7 @@ public:
|
||||
virtual int getVersion() const override { return 13; }
|
||||
virtual int getFormat() const override { return UPX_F_DOS_COM; }
|
||||
virtual const char *getName() const override { return "dos/com"; }
|
||||
virtual const char *getFullName(const options_t *) const override { return "i086-dos16.com"; }
|
||||
virtual const char *getFullName(const Options *) const override { return "i086-dos16.com"; }
|
||||
virtual const int *getCompressionMethods(int method, int level) const override;
|
||||
virtual const int *getFilters() const override;
|
||||
|
||||
|
||||
@ -41,7 +41,7 @@ public:
|
||||
virtual int getVersion() const override { return 14; }
|
||||
virtual int getFormat() const override { return UPX_F_DJGPP2_COFF; }
|
||||
virtual const char *getName() const override { return "djgpp2/coff"; }
|
||||
virtual const char *getFullName(const options_t *) const override {
|
||||
virtual const char *getFullName(const Options *) const override {
|
||||
return "i386-dos32.djgpp2.coff";
|
||||
}
|
||||
virtual const int *getCompressionMethods(int method, int level) const override;
|
||||
|
||||
227
src/p_exe.cpp
227
src/p_exe.cpp
@ -35,9 +35,8 @@
|
||||
static const CLANG_FORMAT_DUMMY_STATEMENT
|
||||
#include "stub/i086-dos16.exe.h"
|
||||
|
||||
#define RSFCRI 4096 // Reserved Space For Compressed Relocation Info
|
||||
#define MAXMATCH 0x2000
|
||||
#define MAXRELOCS (0x8000 - MAXMATCH)
|
||||
#define MAXRELOCSIZE (0x8000 - MAXMATCH)
|
||||
|
||||
#define DI_LIMIT 0xff00 // see the assembly why
|
||||
|
||||
@ -49,9 +48,6 @@ PackExe::PackExe(InputFile *f) : super(f) {
|
||||
bele = &N_BELE_RTP::le_policy;
|
||||
COMPILE_TIME_ASSERT(sizeof(exe_header_t) == 32)
|
||||
COMPILE_TIME_ASSERT_ALIGNED1(exe_header_t)
|
||||
ih_exesize = ih_imagesize = ih_overlay = 0;
|
||||
stack_for_lzma = 0;
|
||||
use_clear_dirty_stack = false;
|
||||
}
|
||||
|
||||
Linker *PackExe::newLinker() const { return new ElfLinkerX86(); }
|
||||
@ -59,8 +55,7 @@ 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"
|
||||
// WARNING: this side effect may persists for later files;
|
||||
// but note that class PackMaster creates per-file local options
|
||||
// (note that class PackMaster creates per-file local options)
|
||||
if (opt->all_methods_use_lzma == 1 && !opt->method_lzma_seen)
|
||||
opt->all_methods_use_lzma = 0;
|
||||
return Packer::getDefaultCompressionMethods_8(method, level, small);
|
||||
@ -125,7 +120,7 @@ void PackExe::addLoaderEpilogue(int flag) {
|
||||
linker->defineSymbol("original_ss", ih.ss);
|
||||
linker->defineSymbol(
|
||||
"reloc_size",
|
||||
(ph.u_len <= DI_LIMIT || (ph.u_len & 0x7fff) >= relocsize ? 0 : MAXRELOCS) - relocsize);
|
||||
(ph.u_len <= DI_LIMIT || (ph.u_len & 0x7fff) >= relocsize ? 0 : MAXRELOCSIZE) - relocsize);
|
||||
}
|
||||
|
||||
void PackExe::buildLoader(const Filter *) {
|
||||
@ -229,18 +224,18 @@ int PackExe::readFileHeader() {
|
||||
ih_overlay = file_size - ih_exesize;
|
||||
if (file_size_u < sizeof(ih) || ((ih.m512 | ih.p512) && ih.m512 + ih.p512 * 512u < sizeof(ih)))
|
||||
throwCantPack("illegal exe header");
|
||||
if (file_size_u < ih_exesize || ih_imagesize <= 0 || ih_imagesize > ih_exesize)
|
||||
if (ih_exesize > file_size_u || ih_imagesize <= 0 || ih_imagesize > ih_exesize)
|
||||
throwCantPack("exe header corrupted");
|
||||
NO_printf("dos/exe header: %d %d %d\n", ih_exesize, ih_imagesize, ih_overlay);
|
||||
return UPX_F_DOS_EXE;
|
||||
}
|
||||
|
||||
bool PackExe::canPack() {
|
||||
if (fn_has_ext(fi->getName(), "sys"))
|
||||
if (fn_has_ext(fi->getName(), "sys")) // dos/sys
|
||||
return false;
|
||||
if (!readFileHeader())
|
||||
return false;
|
||||
if (file_size < 1024)
|
||||
if (file_size < 1024 || ih_imagesize < 512)
|
||||
throwCantPack("file is too small for dos/exe");
|
||||
fi->seek(0x3c, SEEK_SET);
|
||||
LE32 offs;
|
||||
@ -258,13 +253,17 @@ bool PackExe::canPack() {
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs,
|
||||
const unsigned nrelocs, byte *crel, bool *has_9a) {
|
||||
static unsigned optimize_relocs(SPAN_S(byte) image, const unsigned image_size,
|
||||
SPAN_S(const byte) relocs, const unsigned relocnum,
|
||||
SPAN_S(byte) crel, bool *has_9a) {
|
||||
#if WITH_XSPAN >= 2
|
||||
ptr_check_no_overlap(image.data(image_size), image_size, relocs.data(), relocs.size_bytes(),
|
||||
crel.data(), crel.size_bytes());
|
||||
#endif
|
||||
if (opt->exact)
|
||||
throwCantPackExact();
|
||||
|
||||
byte *const crel_save = crel;
|
||||
unsigned i;
|
||||
SPAN_S_VAR(byte, const crel_start, crel);
|
||||
unsigned seg_high = 0;
|
||||
#if 0
|
||||
unsigned seg_low = 0xffffffff;
|
||||
@ -274,19 +273,19 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
|
||||
unsigned linear_high = 0;
|
||||
#endif
|
||||
|
||||
// pass 1 - find 0x9a bounds
|
||||
for (i = 0; i < nrelocs; i++) {
|
||||
// pass 1 - find 0x9a bounds in image
|
||||
for (unsigned i = 0; i < relocnum; i++) {
|
||||
unsigned addr = get_le32(relocs + 4 * i);
|
||||
if (addr >= size - 1)
|
||||
if (addr >= image_size - 1)
|
||||
throwCantPack("unexpected relocation 1");
|
||||
if (addr >= 3 && b[addr - 3] == 0x9a) {
|
||||
unsigned seg = get_le16(b + addr);
|
||||
if (addr >= 3 && image[addr - 3] == 0x9a) {
|
||||
unsigned seg = get_le16(image + addr);
|
||||
if (seg > seg_high)
|
||||
seg_high = seg;
|
||||
#if 0
|
||||
if (seg < seg_low)
|
||||
seg_low = seg;
|
||||
unsigned off = get_le16(b+addr-2);
|
||||
unsigned off = get_le16(image + addr - 2);
|
||||
if (off < off_low)
|
||||
off_low = off;
|
||||
if (off > off_high)
|
||||
@ -308,19 +307,20 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
|
||||
crel += 4; // to be filled in later
|
||||
|
||||
unsigned ones = 0;
|
||||
unsigned es = 0, di, t;
|
||||
i = 0;
|
||||
do {
|
||||
unsigned es = 0;
|
||||
for (unsigned i = 0; i < relocnum;) {
|
||||
unsigned addr = get_le32(relocs + 4 * i);
|
||||
set_le16(crel, di = addr & 0x0f);
|
||||
unsigned di = addr & 0x0f;
|
||||
set_le16(crel + 0, di);
|
||||
set_le16(crel + 2, (addr >> 4) - es);
|
||||
es = addr >> 4;
|
||||
crel += 4;
|
||||
es = addr >> 4;
|
||||
|
||||
for (++i; i < nrelocs; i++) {
|
||||
for (++i; i < relocnum; i++) {
|
||||
unsigned t;
|
||||
addr = get_le32(relocs + 4 * i);
|
||||
// printf ("%x\n",es*16+di);
|
||||
if ((addr - es * 16 > 0xfffe) || (i == nrelocs - 1 && addr - es * 16 > 0xff00)) {
|
||||
NO_printf("%x\n", es * 16 + di);
|
||||
if ((addr - es * 16 > 0xfffe) || (i == relocnum - 1 && addr - es * 16 > 0xff00)) {
|
||||
// segment change
|
||||
t = 1 + (0xffff - di) / 254;
|
||||
memset(crel, 1, t);
|
||||
@ -329,9 +329,9 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
|
||||
break;
|
||||
}
|
||||
unsigned offs = addr - es * 16;
|
||||
if (offs >= 3 && b[es * 16 + offs - 3] == 0x9a && offs > di + 3) {
|
||||
if (offs >= 3 && image[es * 16 + offs - 3] == 0x9a && offs > di + 3) {
|
||||
for (t = di; t < offs - 3; t++)
|
||||
if (b[es * 16 + t] == 0x9a && get_le16(b + es * 16 + t + 3) <= seg_high)
|
||||
if (image[es * 16 + t] == 0x9a && get_le16(image + es * 16 + t + 3) <= seg_high)
|
||||
break;
|
||||
if (t == offs - 3) {
|
||||
// code 0: search for 0x9a
|
||||
@ -342,9 +342,8 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
|
||||
}
|
||||
}
|
||||
t = offs - di;
|
||||
if (t < 2)
|
||||
if ((int) t < 2)
|
||||
throwCantPack("unexpected relocation 2");
|
||||
|
||||
while (t >= 256) {
|
||||
// code 1: add 254, don't reloc
|
||||
*crel++ = 1;
|
||||
@ -354,14 +353,14 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
|
||||
*crel++ = (byte) t;
|
||||
di = offs;
|
||||
}
|
||||
} while (i < nrelocs);
|
||||
}
|
||||
*crel++ = 1;
|
||||
ones++;
|
||||
set_le16(crel_save, ones);
|
||||
set_le16(crel_save + 2, seg_high);
|
||||
set_le16(crel_start, ones);
|
||||
set_le16(crel_start + 2, seg_high);
|
||||
|
||||
// OutputFile::dump("x.rel", crel_save, crel - crel_save);
|
||||
return (unsigned) (crel - crel_save);
|
||||
// OutputFile::dump("x.rel", crel_start, ptr_udiff_bytes(crel, crel_start));
|
||||
return ptr_udiff_bytes(crel, crel_start);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
@ -371,16 +370,14 @@ static unsigned optimize_relocs(byte *b, const unsigned size, const byte *relocs
|
||||
void PackExe::pack(OutputFile *fo) {
|
||||
unsigned ic;
|
||||
|
||||
if (ih.relocs > MAXRELOCS)
|
||||
const unsigned relocnum = ih.relocs;
|
||||
if (relocnum > MAXRELOCSIZE) // early check
|
||||
throwCantPack("too many relocations");
|
||||
checkOverlay(ih_overlay);
|
||||
|
||||
// alloc buffers
|
||||
relocsize = RSFCRI + 4 * ih.relocs;
|
||||
ibuf.alloc(ih_imagesize + 16 + relocsize + 2);
|
||||
obuf.allocForCompression(ih_imagesize + 16 + relocsize + 2);
|
||||
|
||||
// read image
|
||||
// image + space for optimized relocs + safety/alignments
|
||||
ibuf.alloc(ih_imagesize + 4 * relocnum + 1024);
|
||||
fi->seek(ih.headsize16 * 16, SEEK_SET);
|
||||
fi->readx(ibuf, ih_imagesize);
|
||||
|
||||
@ -389,37 +386,41 @@ void PackExe::pack(OutputFile *fo) {
|
||||
device_driver = get_le32(ibuf) == 0xffffffffu;
|
||||
|
||||
// relocations
|
||||
has_9a = false;
|
||||
byte *w = ibuf + ih_imagesize;
|
||||
if (ih.relocs) {
|
||||
byte *wr = w + RSFCRI;
|
||||
|
||||
fi->seek(ih.relocoffs, SEEK_SET);
|
||||
fi->readx(wr, 4 * ih.relocs);
|
||||
|
||||
for (ic = 0; ic < ih.relocs; ic++) {
|
||||
unsigned jc = get_le32(wr + 4 * ic);
|
||||
set_le32(wr + 4 * ic, ((jc >> 16) * 16 + (jc & 0xffff)) & 0xfffff);
|
||||
}
|
||||
qsort(wr, ih.relocs, 4, le32_compare);
|
||||
relocsize = optimize_relocs(ibuf, ih_imagesize, wr, ih.relocs, w, &has_9a);
|
||||
set_le16(w + relocsize, relocsize + 2);
|
||||
relocsize += 2;
|
||||
if (relocsize > MAXRELOCS)
|
||||
throwCantPack("too many relocations");
|
||||
#if 0
|
||||
byte out[9*relocsize/8+1024];
|
||||
unsigned in_len = relocsize;
|
||||
unsigned out_len = 0;
|
||||
ucl_nrv2b_99_compress(w, in_len, out, &out_len, nullptr, 9, nullptr, nullptr);
|
||||
printf("reloc compress: %d -> %d\n", in_len, out_len);
|
||||
#endif
|
||||
} else {
|
||||
relocsize = 0;
|
||||
has_9a = false;
|
||||
if (relocnum) {
|
||||
MemBuffer mb_relocs(4 * relocnum);
|
||||
SPAN_S_VAR(byte, relocs, mb_relocs);
|
||||
fi->seek(ih.relocoffs, SEEK_SET);
|
||||
fi->readx(relocs, 4 * relocnum);
|
||||
|
||||
// dos/exe runs in real-mode, so convert to linear addresses
|
||||
for (ic = 0; ic < relocnum; ic++) {
|
||||
unsigned jc = get_le32(relocs + 4 * ic);
|
||||
set_le32(relocs + 4 * ic, ((jc >> 16) * 16 + (jc & 0xffff)) & 0xfffff);
|
||||
}
|
||||
qsort(raw_bytes(relocs, 4 * relocnum), relocnum, 4, le32_compare);
|
||||
|
||||
SPAN_S_VAR(byte, image, ibuf + 0, ih_imagesize);
|
||||
SPAN_S_VAR(byte, crel, ibuf + ih_imagesize, ibuf);
|
||||
relocsize = optimize_relocs(image, ih_imagesize, relocs, relocnum, crel, &has_9a);
|
||||
set_le16(crel + relocsize, relocsize + 2);
|
||||
relocsize += 2;
|
||||
assert(relocsize >= 11);
|
||||
if (relocsize > MAXRELOCSIZE) // optimize_relocs did not help
|
||||
throwCantPack("too many relocations");
|
||||
#if TESTING && 0
|
||||
unsigned rout_len = MemBuffer::getSizeForCompression(relocsize);
|
||||
MemBuffer rout(rout_len);
|
||||
ucl_nrv2b_99_compress(raw_bytes(crel, relocsize), relocsize, rout, &rout_len, nullptr, 9,
|
||||
nullptr, nullptr);
|
||||
printf("dos/exe reloc compress: %d -> %d\n", relocsize, rout_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
// prepare packheader
|
||||
ph.u_len = ih_imagesize + relocsize;
|
||||
obuf.allocForCompression(ph.u_len);
|
||||
// prepare filter
|
||||
Filter ft(ph.level);
|
||||
// compress (max_match = 8192)
|
||||
@ -511,9 +512,7 @@ void PackExe::pack(OutputFile *fo) {
|
||||
oh.firstreloc = ih.cs * 0x10000 + ih.ip;
|
||||
}
|
||||
|
||||
// g++ 3.1 does not like the following line...
|
||||
oh.relocoffs = offsetof(exe_header_t, firstreloc);
|
||||
// oh.relocoffs = ptr_udiff_bytes(&oh.firstreloc, &oh);
|
||||
|
||||
linker->defineSymbol("destination_segment", oh.ss - ph.c_len / 16 - e_len / 16);
|
||||
linker->defineSymbol("source_segment", e_len / 16 + (copysize - firstcopy) / 16);
|
||||
@ -526,7 +525,7 @@ void PackExe::pack(OutputFile *fo) {
|
||||
linker->defineSymbol("attribute", get_le16(ibuf + 4));
|
||||
linker->defineSymbol("orig_strategy", get_le16(ibuf + 6));
|
||||
|
||||
const unsigned outputlen = sizeof(oh) + lsize + packedsize + eisize;
|
||||
const unsigned outputlen = sizeof(oh) + e_len + packedsize + d_len + eisize;
|
||||
oh.m512 = outputlen & 511;
|
||||
oh.p512 = (outputlen + 511) >> 9;
|
||||
|
||||
@ -538,20 +537,19 @@ void PackExe::pack(OutputFile *fo) {
|
||||
memcpy(loader, getLoader(), lsize);
|
||||
patchPackHeader(loader, e_len);
|
||||
|
||||
NO_fprintf(stderr, "\ne_len=%x d_len=%x c_len=%x oo=%x ulen=%x destp=%x copys=%x images=%x",
|
||||
e_len, d_len, packedsize, ph.overlap_overhead, ph.u_len, /*destpara*/ 0, copysize,
|
||||
ih_imagesize);
|
||||
NO_fprintf(stderr, "\ne_len=%x d_len=%x c_len=%x oo=%x ulen=%x copysize=%x imagesize=%x", e_len,
|
||||
d_len, packedsize, ph.overlap_overhead, ph.u_len, copysize, ih_imagesize);
|
||||
|
||||
// write header + write loader + compressed file
|
||||
#if TESTING
|
||||
if (opt->debug.debug_level)
|
||||
printf("\n%d %d %d %d\n", (int) sizeof(oh), e_len, packedsize, d_len);
|
||||
#endif
|
||||
fo->write(&oh, sizeof(oh));
|
||||
fo->write(loader, e_len); // entry
|
||||
fo->write(obuf, packedsize);
|
||||
fo->write(loader + e_len, d_len); // decompressor
|
||||
fo->write(extra_info, eisize);
|
||||
fo->write(&oh, sizeof(oh)); // program header
|
||||
fo->write(loader, e_len); // entry code
|
||||
fo->write(obuf, packedsize); // compressed data
|
||||
fo->write(loader + e_len, d_len); // decompressor code
|
||||
fo->write(extra_info, eisize); // extra info for unpacking
|
||||
assert(eisize <= 9);
|
||||
NO_printf("%-13s: program hdr : %8u bytes\n", getName(), usizeof(oh));
|
||||
NO_printf("%-13s: entry : %8u bytes\n", getName(), e_len);
|
||||
@ -564,7 +562,7 @@ void PackExe::pack(OutputFile *fo) {
|
||||
|
||||
// copy the overlay
|
||||
copyOverlay(fo, ih_overlay, obuf);
|
||||
// fprintf (stderr,"%x %x\n",relocsize,ph.u_len);
|
||||
NO_fprintf(stderr, "dos/exe %x %x\n", relocsize, ph.u_len);
|
||||
|
||||
// finally check the compression ratio
|
||||
if (!checkFinalCompressionRatio(fo))
|
||||
@ -607,41 +605,46 @@ void PackExe::unpack(OutputFile *fo) {
|
||||
decompress(ibuf + e_len, obuf);
|
||||
|
||||
unsigned imagesize = ih_imagesize;
|
||||
imagesize--;
|
||||
imagesize -= 1;
|
||||
const byte flag = ibuf[imagesize];
|
||||
|
||||
unsigned relocn = 0;
|
||||
SPAN_S_VAR(byte, relocs, obuf + ph.u_len, obuf);
|
||||
|
||||
MemBuffer mb_wrkmem;
|
||||
SPAN_0_VAR(byte, wrkmem, nullptr);
|
||||
// relocations
|
||||
unsigned relocnum = 0;
|
||||
SPAN_S_VAR(const byte, relocstart, obuf + ph.u_len, obuf);
|
||||
MemBuffer mb_relocs;
|
||||
SPAN_0_VAR(byte, relocs, nullptr);
|
||||
if (!(flag & NORELOC)) {
|
||||
relocs -= get_le16(obuf + (ph.u_len - 2));
|
||||
mb_relocs.alloc(4 * MAXRELOCSIZE);
|
||||
relocs = mb_relocs; // => now a SPAN_S
|
||||
|
||||
relocsize = get_le16(obuf + ph.u_len - 2);
|
||||
ph.u_len -= 2;
|
||||
if (relocsize < 11 || relocsize > MAXRELOCSIZE || relocsize >= imagesize)
|
||||
throwCantUnpack("bad relocations");
|
||||
relocstart -= relocsize;
|
||||
|
||||
mb_wrkmem.alloc(4 * MAXRELOCS);
|
||||
wrkmem = mb_wrkmem; // => now a SPAN_S
|
||||
unsigned es = 0, ones = get_le16(relocs);
|
||||
const unsigned seghi = get_le16(relocs + 2);
|
||||
SPAN_S_VAR(const byte, p, relocs + 4);
|
||||
|
||||
// unoptimize_relocs
|
||||
unsigned ones = get_le16(relocstart);
|
||||
const unsigned seg_high = get_le16(relocstart + 2);
|
||||
SPAN_S_VAR(const byte, p, relocstart + 4);
|
||||
unsigned es = 0;
|
||||
while (ones) {
|
||||
unsigned di = get_le16(p);
|
||||
es += get_le16(p + 2);
|
||||
bool dorel = true;
|
||||
for (p += 4; ones && di < 0x10000; p++) {
|
||||
if (dorel) {
|
||||
set_le16(wrkmem + (4 * relocn), di);
|
||||
set_le16(wrkmem + (2 + 4 * relocn++), es);
|
||||
NO_printf("%x\n", es * 16 + di);
|
||||
set_le16(relocs + (4 * relocnum + 0), di);
|
||||
set_le16(relocs + (4 * relocnum + 2), es);
|
||||
NO_printf("dos/exe unreloc %4d %6x\n", relocnum, es * 16 + di);
|
||||
relocnum++;
|
||||
}
|
||||
dorel = true;
|
||||
if (*p == 0) {
|
||||
SPAN_S_VAR(const byte, q, obuf);
|
||||
for (q = obuf + (es * 16 + di); !(*q == 0x9a && get_le16(q + 3) <= seghi);
|
||||
q++) {
|
||||
}
|
||||
di = ptr_diff_bytes(q, obuf + (es * 16)) + 3;
|
||||
SPAN_S_VAR(const byte, q, obuf + (es * 16 + di), obuf);
|
||||
while (!(*q == 0x9a && get_le16(q + 3) <= seg_high))
|
||||
q++;
|
||||
di = ptr_udiff_bytes(q, obuf + (es * 16)) + 3;
|
||||
} else if (*p == 1) {
|
||||
di += 254;
|
||||
if (di < 0x10000)
|
||||
@ -657,16 +660,16 @@ void PackExe::unpack(OutputFile *fo) {
|
||||
memset(&oh, 0, sizeof(oh));
|
||||
oh.ident = 'M' + 'Z' * 256;
|
||||
|
||||
if (relocn) {
|
||||
oh.relocs = relocn;
|
||||
while (relocn & 3)
|
||||
set_le32(wrkmem + (4 * relocn++), 0);
|
||||
if (relocnum) {
|
||||
oh.relocs = relocnum;
|
||||
while (relocnum & 3) // paragraph align
|
||||
set_le32(relocs + (4 * relocnum++), 0);
|
||||
}
|
||||
|
||||
unsigned outputlen = ptr_udiff_bytes(relocs, obuf) + sizeof(oh) + relocn * 4;
|
||||
unsigned outputlen = sizeof(oh) + 4 * relocnum + ptr_udiff_bytes(relocstart, obuf);
|
||||
oh.m512 = outputlen & 511;
|
||||
oh.p512 = (outputlen + 511) >> 9;
|
||||
oh.headsize16 = 2 + relocn / 4;
|
||||
oh.headsize16 = 2 + relocnum / 4;
|
||||
|
||||
oh.max = ih.max;
|
||||
oh.min = ih.min;
|
||||
@ -701,9 +704,9 @@ void PackExe::unpack(OutputFile *fo) {
|
||||
|
||||
// write header + relocations + uncompressed file
|
||||
fo->write(&oh, sizeof(oh));
|
||||
if (relocn)
|
||||
fo->write(wrkmem, relocn * 4);
|
||||
fo->write(obuf, ptr_udiff_bytes(relocs, obuf));
|
||||
if (relocnum)
|
||||
fo->write(relocs, 4 * relocnum);
|
||||
fo->write(obuf, ptr_udiff_bytes(relocstart, obuf));
|
||||
|
||||
// copy the overlay
|
||||
copyOverlay(fo, ih_overlay, obuf);
|
||||
|
||||
18
src/p_exe.h
18
src/p_exe.h
@ -41,7 +41,7 @@ public:
|
||||
virtual int getVersion() const override { return 13; }
|
||||
virtual int getFormat() const override { return UPX_F_DOS_EXE; }
|
||||
virtual const char *getName() const override { return "dos/exe"; }
|
||||
virtual const char *getFullName(const options_t *) const override { return "i086-dos16.exe"; }
|
||||
virtual const char *getFullName(const Options *) const override { return "i086-dos16.exe"; }
|
||||
virtual const int *getCompressionMethods(int method, int level) const override;
|
||||
virtual const int *getFilters() const override;
|
||||
|
||||
@ -90,18 +90,18 @@ protected:
|
||||
|
||||
exe_header_t ih, oh;
|
||||
|
||||
unsigned ih_exesize;
|
||||
unsigned ih_imagesize;
|
||||
unsigned ih_overlay;
|
||||
unsigned relocsize;
|
||||
unsigned ih_exesize = 0;
|
||||
unsigned ih_imagesize = 0;
|
||||
unsigned ih_overlay = 0;
|
||||
unsigned relocsize = 0;
|
||||
|
||||
bool has_9a;
|
||||
bool device_driver;
|
||||
bool has_9a = false;
|
||||
bool device_driver = false;
|
||||
|
||||
enum { NORELOC = 1, USEJUMP = 2, SS = 4, SP = 8, MINMEM = 16, MAXMEM = 32 };
|
||||
|
||||
unsigned stack_for_lzma; // stack size required for lzma
|
||||
bool use_clear_dirty_stack;
|
||||
unsigned stack_for_lzma = 0; // stack size required for lzma
|
||||
bool use_clear_dirty_stack = false;
|
||||
};
|
||||
|
||||
#endif /* already included */
|
||||
|
||||
@ -45,7 +45,7 @@ public:
|
||||
virtual int getVersion() const override { return 13; }
|
||||
virtual int getFormat() const override { return UPX_F_PS1_EXE; }
|
||||
virtual const char *getName() const override { return "ps1/exe"; }
|
||||
virtual const char *getFullName(const options_t *) const override { return "mipsel.r3000-ps1"; }
|
||||
virtual const char *getFullName(const Options *) const override { return "mipsel.r3000-ps1"; }
|
||||
virtual const int *getCompressionMethods(int method, int level) const override;
|
||||
virtual const int *getFilters() const override;
|
||||
|
||||
|
||||
@ -41,7 +41,7 @@ public:
|
||||
virtual int getVersion() const override { return 13; }
|
||||
virtual int getFormat() const override { return UPX_F_DOS_SYS; }
|
||||
virtual const char *getName() const override { return "dos/sys"; }
|
||||
virtual const char *getFullName(const options_t *) const override { return "i086-dos16.sys"; }
|
||||
virtual const char *getFullName(const Options *) const override { return "i086-dos16.sys"; }
|
||||
|
||||
virtual bool canPack() override;
|
||||
|
||||
|
||||
@ -188,15 +188,18 @@ void PackTmt::pack(OutputFile *fo) {
|
||||
checkOverlay(overlay);
|
||||
|
||||
for (unsigned ic = 0; ic < relocnum; ic++)
|
||||
set_le32(relocs + ic * 4, get_le32(relocs + ic * 4) - 4);
|
||||
set_le32(relocs + 4 * ic, get_le32(relocs + 4 * ic) - 4);
|
||||
|
||||
MemBuffer mb_orelocs(4 * relocnum + 8192); // relocations + extra_info
|
||||
SPAN_S_VAR(byte, orelocs, mb_orelocs);
|
||||
unsigned orelocsize =
|
||||
optimizeReloc(relocnum, relocs, orelocs, ibuf, usize, 32, true, &big_relocs);
|
||||
mb_relocs.dealloc(); // done
|
||||
#if 1
|
||||
// write duplicate end marker; why is this here - historical oversight ???
|
||||
orelocs[orelocsize++] = 0;
|
||||
#endif
|
||||
// extra_info
|
||||
orelocs[orelocsize++] = 0; // why is this needed - historical oversight ???
|
||||
set_le32(orelocs + orelocsize, ih.entry); // save original entry point
|
||||
orelocsize += 4;
|
||||
set_le32(orelocs + orelocsize, orelocsize + 4); // save orelocsize
|
||||
@ -303,7 +306,7 @@ void PackTmt::unpack(OutputFile *fo) {
|
||||
const unsigned relocnum = unoptimizeReloc(orelocs, mb_relocs, reloc_image, osize, 32, true);
|
||||
SPAN_S_VAR(byte, relocs, mb_relocs);
|
||||
for (unsigned ic = 0; ic < relocnum; ic++)
|
||||
set_le32(relocs + ic * 4, get_le32(relocs + ic * 4) + 4);
|
||||
set_le32(relocs + 4 * ic, get_le32(relocs + 4 * ic) + 4);
|
||||
|
||||
memcpy(&oh, &ih, sizeof(oh));
|
||||
oh.imagesize = osize;
|
||||
|
||||
@ -41,7 +41,7 @@ public:
|
||||
virtual int getVersion() const override { return 13; }
|
||||
virtual int getFormat() const override { return UPX_F_TMT_ADAM; }
|
||||
virtual const char *getName() const override { return "tmt/adam"; }
|
||||
virtual const char *getFullName(const options_t *) const override {
|
||||
virtual const char *getFullName(const Options *) const override {
|
||||
return "i386-dos32.tmt.adam";
|
||||
}
|
||||
virtual const int *getCompressionMethods(int method, int level) const override;
|
||||
|
||||
@ -223,11 +223,9 @@ void PackTos::buildLoader(const Filter *ft) {
|
||||
#define F_FASTLOAD 0x01 // don't zero heap
|
||||
#define F_ALTLOAD 0x02 // OK to load in alternate ram
|
||||
#define F_ALTALLOC 0x04 // OK to malloc from alt. ram
|
||||
#define F_SMALLTPA \
|
||||
0x08 // used in MagiC: TPA can be allocated
|
||||
// as specified in the program header
|
||||
// rather than the biggest free memory
|
||||
// block
|
||||
#define F_SMALLTPA 0x08
|
||||
// used in MagiC: TPA can be allocated as specified in the program header
|
||||
// rather than the biggest free memory block
|
||||
#define F_MEMFLAGS 0xf0 // reserved for future use
|
||||
#define F_SHTEXT 0x800 // program's text may be shared
|
||||
|
||||
@ -297,26 +295,26 @@ bool PackTos::checkFileHeader() {
|
||||
// relocs
|
||||
**************************************************************************/
|
||||
|
||||
// Check relocation for errors to make sure our loader can handle it.
|
||||
static int check_relocs(const byte *relocs, unsigned rsize, unsigned isize, unsigned *nrelocs,
|
||||
// Check relocation for errors to make sure our loader can handle them
|
||||
static int check_relocs(const byte *relocs, unsigned rsize, unsigned image_size, unsigned *relocnum,
|
||||
unsigned *relocsize, unsigned *overlay) {
|
||||
assert(rsize >= 4);
|
||||
assert(image_size >= 4);
|
||||
unsigned fixup = get_be32(relocs);
|
||||
assert(fixup > 0);
|
||||
unsigned last_fixup = fixup;
|
||||
unsigned i = 4;
|
||||
|
||||
assert(isize >= 4);
|
||||
assert(fixup > 0);
|
||||
|
||||
*nrelocs = 1;
|
||||
*relocnum = 1;
|
||||
for (;;) {
|
||||
if (fixup & 1) // must be word-aligned
|
||||
return -1;
|
||||
if (fixup + 4 > isize) // too far
|
||||
if (fixup + 4 > image_size) // out of bounds
|
||||
return -1;
|
||||
if (i >= rsize) // premature EOF in relocs
|
||||
return -1;
|
||||
unsigned c = relocs[i++];
|
||||
if (c == 0) // end marker
|
||||
if (c == 0) // EOF end marker
|
||||
break;
|
||||
else if (c == 1) // increase fixup, no reloc
|
||||
fixup += 254;
|
||||
@ -328,7 +326,7 @@ static int check_relocs(const byte *relocs, unsigned rsize, unsigned isize, unsi
|
||||
if (fixup - last_fixup < 4) // overlapping relocation
|
||||
return -1;
|
||||
last_fixup = fixup;
|
||||
*nrelocs += 1;
|
||||
*relocnum += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -352,7 +350,7 @@ bool PackTos::canPack() {
|
||||
if (!checkFileHeader())
|
||||
throwCantPack("unsupported header flags");
|
||||
if (file_size < 1024)
|
||||
throwCantPack("program is too small");
|
||||
throwCantPack("program is too small for atari/tos");
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -370,7 +368,7 @@ void PackTos::fileInfo() {
|
||||
|
||||
void PackTos::pack(OutputFile *fo) {
|
||||
unsigned t;
|
||||
unsigned nrelocs = 0;
|
||||
unsigned relocnum = 0;
|
||||
unsigned relocsize = 0;
|
||||
unsigned overlay = 0;
|
||||
|
||||
@ -426,14 +424,14 @@ void PackTos::pack(OutputFile *fo) {
|
||||
} else if (ih.fh_reloc != 0)
|
||||
relocsize = 0;
|
||||
else {
|
||||
int r = check_relocs(ibuf + t, overlay, t, &nrelocs, &relocsize, &overlay);
|
||||
int r = check_relocs(ibuf + t, overlay, t, &relocnum, &relocsize, &overlay);
|
||||
if (r != 0)
|
||||
throwCantPack("bad relocation table");
|
||||
symbols.need_reloc = true;
|
||||
}
|
||||
|
||||
#if TESTING
|
||||
printf("xx2: %d relocs: %d, overlay: %d, t: %d\n", nrelocs, relocsize, overlay, t);
|
||||
printf("xx2: %d relocs: %d, overlay: %d, t: %d\n", relocnum, relocsize, overlay, t);
|
||||
#endif
|
||||
|
||||
checkOverlay(overlay);
|
||||
@ -451,7 +449,7 @@ void PackTos::pack(OutputFile *fo) {
|
||||
// Now the data in ibuf[0..t] looks like this:
|
||||
// text + data + relocs + original file header
|
||||
// After compression this will become the first part of the
|
||||
// data segement. The second part will be the decompressor.
|
||||
// data segment. The second part will be the decompressor.
|
||||
|
||||
// alloc buffer (4096 is for decompressor and the various alignments)
|
||||
obuf.allocForCompression(t, 4096);
|
||||
|
||||
@ -41,7 +41,7 @@ public:
|
||||
virtual int getVersion() const override { return 13; }
|
||||
virtual int getFormat() const override { return UPX_F_ATARI_TOS; }
|
||||
virtual const char *getName() const override { return "atari/tos"; }
|
||||
virtual const char *getFullName(const options_t *) const override { return "m68k-atari.tos"; }
|
||||
virtual const char *getFullName(const Options *) const override { return "m68k-atari.tos"; }
|
||||
virtual const int *getCompressionMethods(int method, int level) const override;
|
||||
virtual const int *getFilters() const override;
|
||||
|
||||
|
||||
@ -62,8 +62,8 @@ Linker *PackW32PeI386::newLinker() const { return new ElfLinkerX86; }
|
||||
**************************************************************************/
|
||||
|
||||
int PackW32PeI386::readFileHeader() {
|
||||
if (fi->st_size() >= 0x206) {
|
||||
char buf[6];
|
||||
if (file_size >= 0x206) {
|
||||
byte buf[6];
|
||||
fi->seek(0x200, SEEK_SET);
|
||||
fi->readx(buf, 6);
|
||||
isrtm = memcmp(buf, "32STUB", 6) == 0;
|
||||
|
||||
@ -39,7 +39,7 @@ public:
|
||||
virtual ~PackW32PeI386();
|
||||
virtual int getFormat() const override { return UPX_F_W32PE_I386; }
|
||||
virtual const char *getName() const override { return isrtm ? "rtm32/pe" : "win32/pe"; }
|
||||
virtual const char *getFullName(const options_t *) const override { return "i386-win32.pe"; }
|
||||
virtual const char *getFullName(const Options *) const override { return "i386-win32.pe"; }
|
||||
virtual const int *getCompressionMethods(int method, int level) const override;
|
||||
virtual const int *getFilters() const override;
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ public:
|
||||
virtual ~PackW64PeAmd64();
|
||||
virtual int getFormat() const override { return UPX_F_W64PE_AMD64; }
|
||||
virtual const char *getName() const override { return "win64/pe"; }
|
||||
virtual const char *getFullName(const options_t *) const override { return "amd64-win64.pe"; }
|
||||
virtual const char *getFullName(const Options *) const override { return "amd64-win64.pe"; }
|
||||
virtual const int *getCompressionMethods(int method, int level) const override;
|
||||
virtual const int *getFilters() const override;
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ public:
|
||||
virtual ~PackW64PeArm64() {}
|
||||
virtual int getFormat() const override { return UPX_F_W64PE_ARM64; }
|
||||
virtual const char *getName() const override { return "win64/arm64"; }
|
||||
virtual const char *getFullName(const options_t *) const override { return "arm64-win64.pe"; }
|
||||
virtual const char *getFullName(const Options *) const override { return "arm64-win64.pe"; }
|
||||
virtual const int *getCompressionMethods(int method, int level) const override;
|
||||
virtual const int *getFilters() const override;
|
||||
|
||||
@ -70,7 +70,7 @@ public:
|
||||
PackW64PeArm64EC(InputFile *f) : super(f) {}
|
||||
virtual int getFormat() const override { return UPX_F_W64PE_ARM64EC; }
|
||||
virtual const char *getName() const override { return "win64/arm64ec"; }
|
||||
virtual const char *getFullName(const options_t *) const override { return "arm64ec-win64.pe"; }
|
||||
virtual const char *getFullName(const Options *) const override { return "arm64ec-win64.pe"; }
|
||||
|
||||
virtual bool canPack() override;
|
||||
};
|
||||
|
||||
@ -39,7 +39,7 @@ public:
|
||||
virtual int getVersion() const override { return 13; }
|
||||
virtual int getFormat() const override { return UPX_F_WATCOM_LE; }
|
||||
virtual const char *getName() const override { return "watcom/le"; }
|
||||
virtual const char *getFullName(const options_t *) const override {
|
||||
virtual const char *getFullName(const Options *) const override {
|
||||
return "i386-dos32.watcom.le";
|
||||
}
|
||||
virtual const int *getCompressionMethods(int method, int level) const override;
|
||||
|
||||
@ -39,7 +39,7 @@ public:
|
||||
virtual ~PackWinCeArm();
|
||||
virtual int getFormat() const override { return UPX_F_WINCE_ARM; }
|
||||
virtual const char *getName() const override { return "wince/arm"; }
|
||||
virtual const char *getFullName(const options_t *) const override { return "arm-wince.pe"; }
|
||||
virtual const char *getFullName(const Options *) const override { return "arm-wince.pe"; }
|
||||
virtual const int *getCompressionMethods(int method, int level) const override;
|
||||
virtual const int *getFilters() const override;
|
||||
virtual void defineFilterSymbols(const Filter *) override {}
|
||||
|
||||
@ -46,7 +46,7 @@ Packer::Packer(InputFile *f)
|
||||
mem_clear(&ph, sizeof(ph));
|
||||
}
|
||||
|
||||
Packer::~Packer() {
|
||||
Packer::~Packer() noexcept {
|
||||
delete uip;
|
||||
uip = nullptr;
|
||||
delete linker;
|
||||
@ -834,27 +834,26 @@ static const char *getIdentstr(unsigned *size, int small) {
|
||||
"\n";
|
||||
static char identtiny[] = UPX_VERSION_STRING4;
|
||||
|
||||
static int done;
|
||||
if (!done && (opt->debug.fake_stub_version[0] || opt->debug.fake_stub_year[0])) {
|
||||
struct strinfo_t {
|
||||
static upx_std_once_flag init_done;
|
||||
upx_std_call_once(init_done, []() noexcept {
|
||||
if (opt->debug.fake_stub_version[0] || opt->debug.fake_stub_year[0]) {
|
||||
struct Ident {
|
||||
char *s;
|
||||
int size;
|
||||
int len;
|
||||
};
|
||||
static const strinfo_t strlist[] = {{identbig, (int) sizeof(identbig)},
|
||||
{identsmall, (int) sizeof(identsmall)},
|
||||
{identtiny, (int) sizeof(identtiny)},
|
||||
static const Ident idents[] = {{identbig, (int) sizeof(identbig) - 1},
|
||||
{identsmall, (int) sizeof(identsmall) - 1},
|
||||
{identtiny, (int) sizeof(identtiny) - 1},
|
||||
{nullptr, 0}};
|
||||
const strinfo_t *iter;
|
||||
|
||||
for (iter = strlist; iter->s; ++iter) {
|
||||
for (const Ident *iter = idents; iter->s; ++iter) {
|
||||
if (opt->debug.fake_stub_version[0])
|
||||
mem_replace(iter->s, iter->size, UPX_VERSION_STRING4, 4,
|
||||
mem_replace(iter->s, iter->len, UPX_VERSION_STRING4, 4,
|
||||
opt->debug.fake_stub_version);
|
||||
if (opt->debug.fake_stub_year[0])
|
||||
mem_replace(iter->s, iter->size, UPX_VERSION_YEAR, 4, opt->debug.fake_stub_year);
|
||||
mem_replace(iter->s, iter->len, UPX_VERSION_YEAR, 4, opt->debug.fake_stub_year);
|
||||
}
|
||||
done = 1;
|
||||
}
|
||||
});
|
||||
|
||||
if (small < 0)
|
||||
small = opt->small;
|
||||
|
||||
@ -112,7 +112,7 @@ protected:
|
||||
Packer(InputFile *f);
|
||||
|
||||
public:
|
||||
virtual ~Packer();
|
||||
virtual ~Packer() noexcept;
|
||||
virtual void assertPacker() const;
|
||||
|
||||
// getVersion() enables detecting forward incompatibility of unpack()
|
||||
@ -121,7 +121,7 @@ public:
|
||||
// A unique integer ID for this executable format. See conf.h.
|
||||
virtual int getFormat() const = 0;
|
||||
virtual const char *getName() const = 0;
|
||||
virtual const char *getFullName(const options_t *) const = 0;
|
||||
virtual const char *getFullName(const Options *) const = 0;
|
||||
virtual const int *getCompressionMethods(int method, int level) const = 0;
|
||||
virtual const int *getFilters() const = 0;
|
||||
|
||||
@ -187,7 +187,7 @@ protected:
|
||||
unsigned overlap_range, upx_compress_config_t const *cconf,
|
||||
int filter_strategy, bool inhibit_compression_check = false);
|
||||
|
||||
// util for verifying overlapping decompresion
|
||||
// util for verifying overlapping decompression
|
||||
// non-destructive test
|
||||
virtual bool testOverlappingDecompression(const byte *buf, const byte *tbuf,
|
||||
unsigned overlap_overhead) const;
|
||||
@ -301,7 +301,7 @@ protected:
|
||||
// compression buffers
|
||||
MemBuffer ibuf; // input
|
||||
MemBuffer obuf; // output
|
||||
unsigned ibufgood; // high-water mark in ibuf (pefile.cpp)
|
||||
unsigned ibufgood = 0; // high-water mark in ibuf (pefile.cpp)
|
||||
|
||||
// UI handler
|
||||
UiPacker *uip = nullptr;
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
|
||||
/*************************************************************************
|
||||
// sort and delta-compress relocations with optional bswap within image
|
||||
// returns number of bytes written to |out|
|
||||
// returns number of bytes written to 'out'
|
||||
**************************************************************************/
|
||||
|
||||
unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(byte) out,
|
||||
@ -38,6 +38,10 @@ unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(by
|
||||
int *big) {
|
||||
assert(bits == 32 || bits == 64);
|
||||
mem_size_assert(1, image_size);
|
||||
#if WITH_XSPAN >= 2
|
||||
ptr_check_no_overlap(relocs.data(), relocs.size_bytes(), image.data(image_size), image_size,
|
||||
out.data(), out.size_bytes());
|
||||
#endif
|
||||
SPAN_P_VAR(byte, fix, out);
|
||||
|
||||
*big = 0;
|
||||
@ -69,7 +73,7 @@ unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(by
|
||||
fix += 4;
|
||||
}
|
||||
pc += delta;
|
||||
if (pc + 4 >= image_size)
|
||||
if (pc + 4 > image_size)
|
||||
throwCantPack("bad reloc[%#x] = %#x", i, pc);
|
||||
if (bswap) {
|
||||
if (bits == 32)
|
||||
@ -84,14 +88,17 @@ unsigned Packer::optimizeReloc(unsigned relocnum, SPAN_P(byte) relocs, SPAN_S(by
|
||||
|
||||
/*************************************************************************
|
||||
// delta-decompress relocations
|
||||
// advances |in|
|
||||
// allocates |out| and returns number of relocs written to |out|
|
||||
// advances 'in'
|
||||
// allocates 'out' and returns number of relocs written to 'out'
|
||||
**************************************************************************/
|
||||
|
||||
unsigned Packer::unoptimizeReloc(SPAN_S(const byte) & in, MemBuffer &out, SPAN_P(byte) image,
|
||||
unsigned image_size, int bits, bool bswap) {
|
||||
assert(bits == 32 || bits == 64);
|
||||
mem_size_assert(1, image_size);
|
||||
#if WITH_XSPAN >= 2
|
||||
ptr_check_no_overlap(in.data(), in.size_bytes(), image.data(image_size), image_size);
|
||||
#endif
|
||||
SPAN_S_VAR(const byte, fix, in);
|
||||
|
||||
// count
|
||||
@ -125,7 +132,7 @@ unsigned Packer::unoptimizeReloc(SPAN_S(const byte) & in, MemBuffer &out, SPAN_P
|
||||
if ((int) delta < 4)
|
||||
throwCantUnpack("overlapping fixups");
|
||||
pc += delta;
|
||||
if (pc + 4 >= image_size)
|
||||
if (pc + 4 > image_size)
|
||||
throwCantUnpack("bad reloc[%#x] = %#x", i, pc);
|
||||
*relocs++ = pc;
|
||||
if (bswap && image != nullptr) {
|
||||
|
||||
133
src/packmast.cpp
133
src/packmast.cpp
@ -59,34 +59,37 @@
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
PackMaster::PackMaster(InputFile *f, options_t *o) : fi(f), p(nullptr) {
|
||||
PackMaster::PackMaster(InputFile *f, Options *o) noexcept : fi(f) {
|
||||
// replace global options with local options
|
||||
if (o != nullptr) {
|
||||
#if WITH_THREADS
|
||||
std::lock_guard<std::mutex> lock(opt_lock_mutex);
|
||||
#endif
|
||||
saved_opt = o;
|
||||
if (o) {
|
||||
memcpy(&this->local_options, o, sizeof(*o)); // struct copy
|
||||
opt = &this->local_options;
|
||||
}
|
||||
}
|
||||
|
||||
PackMaster::~PackMaster() {
|
||||
fi = nullptr;
|
||||
delete p;
|
||||
p = nullptr;
|
||||
PackMaster::~PackMaster() noexcept {
|
||||
delete packer;
|
||||
packer = nullptr;
|
||||
// restore global options
|
||||
if (saved_opt)
|
||||
if (saved_opt != nullptr) {
|
||||
#if WITH_THREADS
|
||||
std::lock_guard<std::mutex> lock(opt_lock_mutex);
|
||||
#endif
|
||||
opt = saved_opt;
|
||||
saved_opt = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
static Packer *try_pack(Packer *p, void *user) {
|
||||
if (p == nullptr)
|
||||
return nullptr;
|
||||
static Packer *try_can_pack(Packer *p, void *user) {
|
||||
InputFile *f = (InputFile *) user;
|
||||
p->assertPacker();
|
||||
try {
|
||||
p->initPackHeader();
|
||||
f->seek(0, SEEK_SET);
|
||||
@ -105,11 +108,8 @@ static Packer *try_pack(Packer *p, void *user) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static Packer *try_unpack(Packer *p, void *user) {
|
||||
if (p == nullptr)
|
||||
return nullptr;
|
||||
static Packer *try_can_unpack(Packer *p, void *user) {
|
||||
InputFile *f = (InputFile *) user;
|
||||
p->assertPacker();
|
||||
try {
|
||||
p->initPackHeader();
|
||||
f->seek(0, SEEK_SET);
|
||||
@ -123,6 +123,7 @@ static Packer *try_unpack(Packer *p, void *user) {
|
||||
// see canUnpack() in packer.h
|
||||
}
|
||||
} catch (const IOException &) {
|
||||
// ignored
|
||||
} catch (...) {
|
||||
delete p;
|
||||
throw;
|
||||
@ -135,41 +136,40 @@ static Packer *try_unpack(Packer *p, void *user) {
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const options_t *o,
|
||||
void *user) {
|
||||
Packer *p = nullptr;
|
||||
/*static*/
|
||||
Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const Options *o, void *user) {
|
||||
|
||||
#define D(Klass) \
|
||||
ACC_BLOCK_BEGIN \
|
||||
Klass *const kp = new Klass(f); \
|
||||
COMPILE_TIME_ASSERT(std::is_nothrow_destructible_v<Klass>) \
|
||||
Klass *kp = new Klass(f); \
|
||||
kp->assertPacker(); \
|
||||
if (o->debug.debug_level) \
|
||||
fprintf(stderr, "visitAllPackers: (ver=%d, fmt=%3d) %s\n", kp->getVersion(), \
|
||||
kp->getFormat(), #Klass); \
|
||||
if ((p = func(kp, user)) != nullptr) \
|
||||
Packer *p = func(kp, user); \
|
||||
if (p != nullptr) \
|
||||
return p; \
|
||||
ACC_BLOCK_END
|
||||
|
||||
// note: order of tries is important !
|
||||
// NOTE: order of tries is important !!!
|
||||
|
||||
//
|
||||
// .exe
|
||||
//
|
||||
if (!o->dos_exe.force_stub) {
|
||||
// dos32
|
||||
D(PackDjgpp2);
|
||||
D(PackTmt);
|
||||
D(PackWcle);
|
||||
// Windows
|
||||
// D(PackW64PeArm64EC); // NOT YET IMPLEMENTED
|
||||
// D(PackW64PeArm64); // NOT YET IMPLEMENTED
|
||||
D(PackW64PeAmd64);
|
||||
D(PackW32PeI386);
|
||||
}
|
||||
D(PackWinCeArm);
|
||||
D(PackExe);
|
||||
|
||||
//
|
||||
// atari
|
||||
//
|
||||
D(PackTos);
|
||||
}
|
||||
D(PackExe); // dos/exe
|
||||
|
||||
//
|
||||
// linux kernel
|
||||
@ -210,18 +210,7 @@ Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const optio
|
||||
D(PackMachFat); // cafebabe conflict
|
||||
D(PackLinuxI386); // cafebabe conflict
|
||||
|
||||
//
|
||||
// psone
|
||||
//
|
||||
D(PackPs1);
|
||||
|
||||
//
|
||||
// .sys and .com
|
||||
//
|
||||
D(PackSys);
|
||||
D(PackCom);
|
||||
|
||||
// Mach (macOS)
|
||||
// Mach (Darwin / macOS)
|
||||
D(PackDylibAMD64);
|
||||
D(PackMachPPC32); // TODO: this works with upx 3.91..3.94 but got broken in 3.95; FIXME
|
||||
D(PackMachI386);
|
||||
@ -235,24 +224,30 @@ Packer *PackMaster::visitAllPackers(visit_func_t func, InputFile *f, const optio
|
||||
// D(PackDylibI386);
|
||||
// D(PackDylibPPC32);
|
||||
|
||||
//
|
||||
// misc
|
||||
//
|
||||
D(PackTos); // atari/tos
|
||||
D(PackPs1); // ps1/exe
|
||||
D(PackSys); // dos/sys
|
||||
D(PackCom); // dos/com
|
||||
|
||||
return nullptr;
|
||||
#undef D
|
||||
}
|
||||
|
||||
Packer *PackMaster::getPacker(InputFile *f) {
|
||||
Packer *pp = visitAllPackers(try_pack, f, opt, f);
|
||||
if (!pp)
|
||||
/*static*/ Packer *PackMaster::getPacker(InputFile *f) {
|
||||
Packer *p = visitAllPackers(try_can_pack, f, opt, f);
|
||||
if (!p)
|
||||
throwUnknownExecutableFormat();
|
||||
pp->assertPacker();
|
||||
return pp;
|
||||
return p;
|
||||
}
|
||||
|
||||
Packer *PackMaster::getUnpacker(InputFile *f) {
|
||||
Packer *pp = visitAllPackers(try_unpack, f, opt, f);
|
||||
if (!pp)
|
||||
/*static*/ Packer *PackMaster::getUnpacker(InputFile *f) {
|
||||
Packer *p = visitAllPackers(try_can_unpack, f, opt, f);
|
||||
if (!p)
|
||||
throwNotPacked();
|
||||
pp->assertPacker();
|
||||
return pp;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
@ -260,39 +255,37 @@ Packer *PackMaster::getUnpacker(InputFile *f) {
|
||||
**************************************************************************/
|
||||
|
||||
void PackMaster::pack(OutputFile *fo) {
|
||||
p = getPacker(fi);
|
||||
fi = nullptr;
|
||||
p->doPack(fo);
|
||||
assert(packer == nullptr);
|
||||
packer = getPacker(fi);
|
||||
packer->doPack(fo);
|
||||
}
|
||||
|
||||
void PackMaster::unpack(OutputFile *fo) {
|
||||
p = getUnpacker(fi);
|
||||
p->assertPacker();
|
||||
fi = nullptr;
|
||||
p->doUnpack(fo);
|
||||
assert(packer == nullptr);
|
||||
packer = getUnpacker(fi);
|
||||
packer->doUnpack(fo);
|
||||
}
|
||||
|
||||
void PackMaster::test() {
|
||||
p = getUnpacker(fi);
|
||||
fi = nullptr;
|
||||
p->doTest();
|
||||
assert(packer == nullptr);
|
||||
packer = getUnpacker(fi);
|
||||
packer->doTest();
|
||||
}
|
||||
|
||||
void PackMaster::list() {
|
||||
p = getUnpacker(fi);
|
||||
fi = nullptr;
|
||||
p->doList();
|
||||
assert(packer == nullptr);
|
||||
packer = getUnpacker(fi);
|
||||
packer->doList();
|
||||
}
|
||||
|
||||
void PackMaster::fileInfo() {
|
||||
p = visitAllPackers(try_unpack, fi, opt, fi);
|
||||
if (!p)
|
||||
p = visitAllPackers(try_pack, fi, opt, fi);
|
||||
if (!p)
|
||||
assert(packer == nullptr);
|
||||
packer = visitAllPackers(try_can_unpack, fi, opt, fi);
|
||||
if (!packer)
|
||||
packer = visitAllPackers(try_can_pack, fi, opt, fi);
|
||||
if (!packer)
|
||||
throwUnknownExecutableFormat(nullptr, 1); // make a warning here
|
||||
p->assertPacker();
|
||||
fi = nullptr;
|
||||
p->doFileInfo();
|
||||
packer->doFileInfo();
|
||||
}
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
|
||||
@ -32,13 +32,13 @@ class InputFile;
|
||||
class OutputFile;
|
||||
|
||||
/*************************************************************************
|
||||
// interface for work.cpp
|
||||
// dispatch to a concrete subclass of class Packer; see work.cpp
|
||||
**************************************************************************/
|
||||
|
||||
class PackMaster final {
|
||||
public:
|
||||
PackMaster(InputFile *f, options_t *o = nullptr);
|
||||
~PackMaster();
|
||||
PackMaster(InputFile *f, Options *o = nullptr) noexcept;
|
||||
~PackMaster() noexcept;
|
||||
|
||||
void pack(OutputFile *fo);
|
||||
void unpack(OutputFile *fo);
|
||||
@ -47,18 +47,18 @@ public:
|
||||
void fileInfo();
|
||||
|
||||
typedef Packer *(*visit_func_t)(Packer *p, void *user);
|
||||
static Packer *visitAllPackers(visit_func_t, InputFile *f, const options_t *, void *user);
|
||||
static Packer *visitAllPackers(visit_func_t, InputFile *f, const Options *, void *user);
|
||||
|
||||
private:
|
||||
InputFile *fi = nullptr;
|
||||
Packer *p = nullptr;
|
||||
Packer *packer = nullptr; // owner
|
||||
InputFile *fi = nullptr; // reference
|
||||
|
||||
static Packer *getPacker(InputFile *f);
|
||||
static Packer *getUnpacker(InputFile *f);
|
||||
|
||||
// setup local options for each file
|
||||
options_t local_options;
|
||||
options_t *saved_opt = nullptr;
|
||||
Options local_options;
|
||||
Options *saved_opt = nullptr;
|
||||
};
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
|
||||
117
src/pefile.cpp
117
src/pefile.cpp
@ -140,7 +140,7 @@ bool PeFile::testUnpackVersion(int version) const {
|
||||
if (cpu >= IMAGE_FILE_MACHINE_I386 && cpu <= 0x150) // what is this 0x150 ???
|
||||
return UPX_F_W32PE_I386;
|
||||
|
||||
// other or unkown (alpha, mips, etc.)
|
||||
// other or unknown (alpha, mips, etc.)
|
||||
throwCantPack("pefile: unsupported machine %#x", cpu);
|
||||
return 0; // pacify msvc
|
||||
}
|
||||
@ -274,6 +274,19 @@ void PeFile::Interval::dump() const {
|
||||
// relocation handling
|
||||
**************************************************************************/
|
||||
|
||||
namespace {
|
||||
struct FixDeleter { // don't leak memory on exceptions
|
||||
LE32 **fix;
|
||||
size_t n;
|
||||
~FixDeleter() noexcept {
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
delete[] fix[i];
|
||||
fix[i] = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
struct alignas(1) PeFile::Reloc::reloc {
|
||||
LE32 pagestart;
|
||||
LE32 size;
|
||||
@ -371,17 +384,21 @@ void PeFile32::processRelocs() // pass1
|
||||
}
|
||||
mb_orelocs.alloc(1);
|
||||
orelocs = mb_orelocs; // => orelocs now is a SPAN_S
|
||||
orelocs[0] = 0; // clear
|
||||
sorelocs = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for (ic = 15; ic > 3; ic--)
|
||||
for (ic = 4; ic < 16; ic++)
|
||||
if (counts[ic])
|
||||
infoWarning("skipping unsupported relocation type %d (%d)", ic, counts[ic]);
|
||||
|
||||
LE32 *fix[4];
|
||||
for (; ic; ic--)
|
||||
FixDeleter fixdel{fix, 0}; // don't leak memory
|
||||
for (ic = 0; ic < 4; ic++) {
|
||||
fix[ic] = New(LE32, counts[ic]);
|
||||
fixdel.n += 1;
|
||||
}
|
||||
|
||||
unsigned xcounts[4];
|
||||
memset(xcounts, 0, sizeof(xcounts));
|
||||
@ -420,7 +437,6 @@ void PeFile32::processRelocs() // pass1
|
||||
orelocs = mb_orelocs; // => orelocs now is a SPAN_S
|
||||
sorelocs = optimizeReloc(xcounts[3], (byte *) fix[3], orelocs, ibuf + rvamin, ibufgood - rvamin,
|
||||
32, true, &big_relocs);
|
||||
delete[] fix[3];
|
||||
|
||||
// Malware that hides behind UPX often has PE header info that is
|
||||
// deliberately corrupt. Sometimes it is even tuned to cause us trouble!
|
||||
@ -433,7 +449,6 @@ void PeFile32::processRelocs() // pass1
|
||||
for (ic = 2; ic; ic--) {
|
||||
memcpy(orelocs + sorelocs, fix[ic], 4 * xcounts[ic]);
|
||||
sorelocs += 4 * xcounts[ic];
|
||||
delete[] fix[ic];
|
||||
|
||||
set_le32(orelocs + sorelocs, 0);
|
||||
if (xcounts[ic]) {
|
||||
@ -471,13 +486,16 @@ void PeFile64::processRelocs() // pass1
|
||||
return;
|
||||
}
|
||||
|
||||
for (ic = 15; ic; ic--)
|
||||
for (ic = 0; ic < 16; ic++)
|
||||
if (ic != 10 && counts[ic])
|
||||
infoWarning("skipping unsupported relocation type %d (%d)", ic, counts[ic]);
|
||||
|
||||
LE32 *fix[16];
|
||||
for (ic = 15; ic; ic--)
|
||||
FixDeleter fixdel{fix, 0}; // don't leak memory
|
||||
for (ic = 0; ic < 16; ic++) {
|
||||
fix[ic] = New(LE32, counts[ic]);
|
||||
fixdel.n += 1;
|
||||
}
|
||||
|
||||
unsigned xcounts[16];
|
||||
memset(xcounts, 0, sizeof(xcounts));
|
||||
@ -495,7 +513,7 @@ void PeFile64::processRelocs() // pass1
|
||||
}
|
||||
|
||||
// remove duplicated records
|
||||
for (ic = 1; ic <= 15; ic++) {
|
||||
for (ic = 1; ic < 16; ic++) {
|
||||
qsort(fix[ic], xcounts[ic], 4, le32_compare);
|
||||
unsigned prev = ~0u;
|
||||
unsigned jc = 0;
|
||||
@ -520,9 +538,6 @@ void PeFile64::processRelocs() // pass1
|
||||
sorelocs = optimizeReloc(xcounts[10], (byte *) fix[10], orelocs, ibuf + rvamin,
|
||||
ibufgood - rvamin, 64, true, &big_relocs);
|
||||
|
||||
for (ic = 15; ic; ic--)
|
||||
delete[] fix[ic];
|
||||
|
||||
#if 0
|
||||
// Malware that hides behind UPX often has PE header info that is
|
||||
// deliberately corrupt. Sometimes it is even tuned to cause us trouble!
|
||||
@ -536,7 +551,6 @@ void PeFile64::processRelocs() // pass1
|
||||
{
|
||||
memcpy(orelocs + sorelocs,fix[ic],4 * xcounts[ic]);
|
||||
sorelocs += 4 * xcounts[ic];
|
||||
delete [] fix[ic];
|
||||
|
||||
set_le32(orelocs + sorelocs,0);
|
||||
if (xcounts[ic])
|
||||
@ -574,7 +588,7 @@ const LE32 &PeFile::IDADDR(unsigned x) const { return iddirs[x].vaddr; }
|
||||
in the sorted order.
|
||||
*/
|
||||
|
||||
class PeFile::ImportLinker : public ElfLinkerAMD64 {
|
||||
class PeFile::ImportLinker final : public ElfLinkerAMD64 {
|
||||
struct tstr : private ::noncopyable {
|
||||
char *s = nullptr;
|
||||
explicit tstr(char *str) : s(str) {}
|
||||
@ -833,7 +847,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
|
||||
import_desc *const im_save = im;
|
||||
if (IDADDR(PEDIR_IMPORT)) {
|
||||
for (;; ++dllnum, ++im) {
|
||||
unsigned const skip2 = ptr_diff_bytes(im, ibuf);
|
||||
unsigned const skip2 = ptr_udiff_bytes(im, ibuf);
|
||||
(void) ibuf.subref("bad import %#x", skip2, sizeof(*im));
|
||||
if (!im->dllname)
|
||||
break;
|
||||
@ -853,25 +867,17 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
|
||||
static int __acc_cdecl_qsort compare(const void *p1, const void *p2) {
|
||||
const udll *u1 = *(const udll *const *) p1;
|
||||
const udll *u2 = *(const udll *const *) p2;
|
||||
if (u1->isk32)
|
||||
return -1;
|
||||
if (u2->isk32)
|
||||
return 1;
|
||||
if (!*u1->lookupt)
|
||||
return 1;
|
||||
if (!*u2->lookupt)
|
||||
return -1;
|
||||
if (u1->isk32 != u2->isk32)
|
||||
return u1->isk32 ? -1 : 1;
|
||||
if ((*u1->lookupt != 0) != (*u2->lookupt != 0))
|
||||
return (*u1->lookupt != 0) ? -1 : 1;
|
||||
int rc = strcasecmp(u1->name, u2->name);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (u1->ordinal)
|
||||
return -1;
|
||||
if (u2->ordinal)
|
||||
return 1;
|
||||
if (!u1->shname)
|
||||
return 1;
|
||||
if (!u2->shname)
|
||||
return -1;
|
||||
if ((u1->ordinal != 0) != (u2->ordinal != 0))
|
||||
return (u1->ordinal != 0) ? -1 : 1;
|
||||
if ((u1->shname != nullptr) != (u2->shname != nullptr))
|
||||
return (u1->shname != nullptr) ? -1 : 1;
|
||||
rc = (int) (upx_safe_strlen(u1->shname) - upx_safe_strlen(u2->shname));
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -904,8 +910,8 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
|
||||
importbyordinal = true;
|
||||
soimport += 2; // ordinal num: 2 bytes
|
||||
dlls[ic].ordinal = *tarr & 0xffff;
|
||||
} else // it's an import by name
|
||||
{
|
||||
} else {
|
||||
// it's an import by name
|
||||
IPTR_VAR(const byte, const name, ibuf + *tarr + 2);
|
||||
unsigned len = strlen(name);
|
||||
soimport += len + 1;
|
||||
@ -919,9 +925,12 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
|
||||
mb_oimport.clear();
|
||||
oimport = mb_oimport;
|
||||
|
||||
qsort(idlls, dllnum, sizeof(udll *), udll::compare);
|
||||
qsort(idlls, dllnum, sizeof(*idlls), udll::compare);
|
||||
|
||||
info("Processing imports: %d DLLs", dllnum);
|
||||
for (ic = 0; ic < dllnum; ic++) {
|
||||
info(" DLL %3d %s %s", ic, idlls[ic]->name, idlls[ic]->shname);
|
||||
}
|
||||
|
||||
ilinker = new ImportLinker(sizeof(LEXX));
|
||||
// create the new import table
|
||||
@ -981,7 +990,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
|
||||
}
|
||||
ppi++;
|
||||
|
||||
unsigned esize = ptr_diff_bytes(tarr, idlls[ic]->lookupt);
|
||||
unsigned esize = ptr_udiff_bytes(tarr, idlls[ic]->lookupt);
|
||||
lookups.add(idlls[ic]->lookupt, esize);
|
||||
if (ptr_diff_bytes(ibuf.subref("bad import name %#x", idlls[ic]->iat, 1),
|
||||
(char *) idlls[ic]->lookupt) != 0) {
|
||||
@ -1299,7 +1308,7 @@ void PeFile::processTls1(Interval *iv, typename tls_traits<LEXX>::cb_value_t ima
|
||||
unsigned const take1 = sizeof(tls);
|
||||
unsigned const skip1 = IDADDR(PEDIR_TLS);
|
||||
memcpy(otls, ibuf.subref("bad tls %#x", skip1, take1), take1);
|
||||
// WARNING: this can acces data in BSS
|
||||
// WARNING: this can access data in BSS
|
||||
unsigned const take3 = sotls - sizeof(tls);
|
||||
memcpy(otls + sizeof(tls), ibuf.subref("bad tls %#x", tlsdatastart, take3), take3);
|
||||
tlsindex = tlsp->tlsindex - imagebase;
|
||||
@ -1887,6 +1896,7 @@ void PeFile::processResources(Resource *res) {
|
||||
soresources = ptr_diff_bytes(ores, oresources);
|
||||
|
||||
delete[] keep_icons;
|
||||
keep_icons = nullptr;
|
||||
if (!res->clear()) {
|
||||
// The area occupied by the resource directory is not continuous
|
||||
// so to still support uncompression, I can't zero this area.
|
||||
@ -2637,6 +2647,16 @@ void PeFile::rebuildTls() {
|
||||
// this is an easy one : just do nothing ;-)
|
||||
}
|
||||
|
||||
namespace {
|
||||
template <class T>
|
||||
struct VPtr {
|
||||
static_assert(sizeof(T) == 1);
|
||||
SPAN_S(T) ptr;
|
||||
size_t vaddr;
|
||||
auto operator+(size_t n) const { return ptr + mem_size(sizeof(T), n - vaddr); }
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void PeFile::rebuildResources(SPAN_S(byte) & extra_info, unsigned lastvaddr) {
|
||||
if (ODSIZE(PEDIR_RESOURCE) == 0 || IDSIZE(PEDIR_RESOURCE) == 0)
|
||||
return;
|
||||
@ -2646,12 +2666,13 @@ void PeFile::rebuildResources(SPAN_S(byte) & extra_info, unsigned lastvaddr) {
|
||||
|
||||
const unsigned vaddr = IDADDR(PEDIR_RESOURCE);
|
||||
|
||||
if (lastvaddr > vaddr || (vaddr - lastvaddr) > ibuf.getSize())
|
||||
if (vaddr < lastvaddr || (vaddr - lastvaddr) > ibuf.getSize())
|
||||
throwCantUnpack("corrupted PE header");
|
||||
|
||||
// TODO: introduce WildPtr for "virtual pointer" pointing before a buffer
|
||||
const byte *r = ibuf.raw_bytes(0) - lastvaddr;
|
||||
Resource res(r + vaddr, ibuf, ibuf + ibuf.getSize());
|
||||
// INFO: use VPtr for "virtual pointer" pointing before a buffer
|
||||
//// const byte *const r = ibuf.raw_bytes(0) - lastvaddr;
|
||||
VPtr<const byte> const r{ibuf, lastvaddr};
|
||||
Resource res(raw_bytes(r + vaddr, 0), ibuf, ibuf + ibuf.getSize());
|
||||
while (res.next())
|
||||
if (res.offs() > vaddr) {
|
||||
ICHECK(r + (res.offs() - 4), 4);
|
||||
@ -2702,8 +2723,9 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
|
||||
}
|
||||
sdllnames = ALIGN_UP(sdllnames, 2u);
|
||||
|
||||
// TODO: introduce WildPtr for "virtual pointer" pointing before a buffer
|
||||
byte *const Obuf = obuf.raw_bytes(0) - rvamin;
|
||||
// INFO: use VPtr for "virtual pointer" pointing before a buffer
|
||||
//// byte *const Obuf = obuf.raw_bytes(0) - rvamin;
|
||||
VPtr<byte> const Obuf{obuf, rvamin};
|
||||
#if 0
|
||||
import_desc * const im0 = (import_desc*) (Obuf + ODADDR(PEDIR_IMPORT));
|
||||
import_desc *im = im0;
|
||||
@ -2711,9 +2733,10 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
|
||||
byte *importednames = dllnames + sdllnames;
|
||||
byte * const importednames_start = importednames;
|
||||
#else
|
||||
SPAN_S_VAR(import_desc, const im0, (import_desc *) (Obuf + ODADDR(PEDIR_IMPORT)), obuf);
|
||||
SPAN_S_VAR(import_desc, const im0, (import_desc *) raw_bytes(Obuf + ODADDR(PEDIR_IMPORT), 0),
|
||||
obuf);
|
||||
SPAN_S_VAR(import_desc, im, im0);
|
||||
SPAN_0_VAR(byte, dllnames, inamespos ? Obuf + inamespos : nullptr, obuf);
|
||||
SPAN_0_VAR(byte, dllnames, inamespos ? raw_bytes(Obuf + inamespos, 0) : nullptr, obuf);
|
||||
SPAN_0_VAR(byte, importednames, inamespos ? dllnames + sdllnames : nullptr);
|
||||
SPAN_0_VAR(byte, const importednames_start, importednames);
|
||||
#endif
|
||||
@ -2728,7 +2751,7 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
|
||||
if (inamespos) {
|
||||
// now I rebuild the dll names
|
||||
omemcpy(dllnames, dname, dlen + 1);
|
||||
im->dllname = ptr_udiff_bytes(dllnames, Obuf);
|
||||
im->dllname = ptr_udiff_bytes(dllnames, obuf) + rvamin;
|
||||
//;;;printf("\ndll: %s:",dllnames);
|
||||
dllnames += dlen + 1;
|
||||
} else {
|
||||
@ -2738,7 +2761,7 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
|
||||
if (set_oft)
|
||||
im->oft = iatoffs;
|
||||
|
||||
OPTR_VAR(LEXX, newiat, (LEXX *) (Obuf + iatoffs));
|
||||
OPTR_VAR(LEXX, newiat, (LEXX *) raw_bytes(Obuf + iatoffs, 0));
|
||||
|
||||
// restore the imported names+ordinals
|
||||
for (p += 8; *p; ++newiat)
|
||||
@ -2749,7 +2772,7 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
|
||||
importednames -= 1;
|
||||
omemcpy(importednames + 2, p, ilen);
|
||||
//;;;printf(" %s",importednames+2);
|
||||
*newiat = ptr_udiff_bytes(importednames, Obuf);
|
||||
*newiat = ptr_udiff_bytes(importednames, obuf) + rvamin;
|
||||
importednames += 2 + ilen;
|
||||
} else {
|
||||
// Beware overlap!
|
||||
@ -2986,7 +3009,7 @@ void PeFile32::readPeHeader() {
|
||||
void PeFile32::pack0(OutputFile *fo, unsigned subsystem_mask, upx_uint64_t default_imagebase,
|
||||
bool last_section_rsrc_only) {
|
||||
super::pack0<LE32>(fo, ih, oh, subsystem_mask, default_imagebase, last_section_rsrc_only);
|
||||
infoWarning("End of PeFile32::pack0");
|
||||
// infoWarning("End of PeFile32::pack0");
|
||||
}
|
||||
|
||||
void PeFile32::unpack(OutputFile *fo) {
|
||||
|
||||
@ -147,7 +147,7 @@ protected:
|
||||
unsigned sotls;
|
||||
unsigned tlsindex;
|
||||
unsigned tlscb_ptr;
|
||||
unsigned tls_handler_offset;
|
||||
unsigned tls_handler_offset = 0;
|
||||
bool use_tls_callbacks = false;
|
||||
|
||||
void processLoadConf(Reloc *, const Interval *, unsigned);
|
||||
@ -288,7 +288,7 @@ protected:
|
||||
enum {
|
||||
IMAGE_SUBSYSTEM_UNKNOWN = 0,
|
||||
IMAGE_SUBSYSTEM_NATIVE = 1,
|
||||
IMAGE_SUBSYSTEM_WINDOWS_GUI = 2, // Grapical
|
||||
IMAGE_SUBSYSTEM_WINDOWS_GUI = 2, // Graphical
|
||||
IMAGE_SUBSYSTEM_WINDOWS_CUI = 3, // Character-mode
|
||||
IMAGE_SUBSYSTEM_WINDOWS_OS2_CUI = 5,
|
||||
IMAGE_SUBSYSTEM_WINDOWS_POSIX_CUI = 7,
|
||||
|
||||
@ -182,7 +182,7 @@ UiPacker::UiPacker(const Packer *p_) : ui_pass(0), ui_total_passes(0), p(p_), s(
|
||||
s->mode = M_CB_SCREEN;
|
||||
}
|
||||
|
||||
UiPacker::~UiPacker() {
|
||||
UiPacker::~UiPacker() noexcept {
|
||||
cb.reset();
|
||||
delete s;
|
||||
s = nullptr;
|
||||
|
||||
2
src/ui.h
2
src/ui.h
@ -39,7 +39,7 @@ public:
|
||||
UiPacker(const Packer *p_);
|
||||
|
||||
public:
|
||||
virtual ~UiPacker();
|
||||
virtual ~UiPacker() noexcept;
|
||||
|
||||
static void uiConfirmUpdate();
|
||||
static void uiPackTotal();
|
||||
|
||||
@ -74,7 +74,7 @@ MemBuffer::MemBuffer(upx_uint64_t bytes) {
|
||||
debug_set(debug.last_return_address_alloc, upx_return_address());
|
||||
}
|
||||
|
||||
MemBuffer::~MemBuffer() { this->dealloc(); }
|
||||
MemBuffer::~MemBuffer() noexcept { this->dealloc(); }
|
||||
|
||||
// similar to BoundedPtr, except checks only at creation
|
||||
// skip == offset, take == size_in_bytes
|
||||
@ -215,19 +215,19 @@ void MemBuffer::alloc(upx_uint64_t bytes) {
|
||||
set_ne32(p + size_in_bytes + 4, stats.global_alloc_counter);
|
||||
}
|
||||
ptr = (pointer) (void *) p;
|
||||
#if !defined(__SANITIZE_ADDRESS__) && 0
|
||||
fill(0, size_in_bytes, (rand() & 0xff) | 1); // debug
|
||||
#if DEBUG
|
||||
memset(ptr, 0xff, size_in_bytes);
|
||||
(void) VALGRIND_MAKE_MEM_UNDEFINED(ptr, size_in_bytes);
|
||||
#endif
|
||||
stats.global_alloc_counter += 1;
|
||||
stats.global_total_bytes += size_in_bytes;
|
||||
stats.global_total_active_bytes += size_in_bytes;
|
||||
#if DEBUG
|
||||
#if DEBUG || 1
|
||||
checkState();
|
||||
#endif
|
||||
}
|
||||
|
||||
void MemBuffer::dealloc() {
|
||||
void MemBuffer::dealloc() noexcept {
|
||||
if (ptr != nullptr) {
|
||||
debug_set(debug.last_return_address_dealloc, upx_return_address());
|
||||
checkState();
|
||||
|
||||
@ -46,11 +46,12 @@ protected:
|
||||
size_type size_in_bytes;
|
||||
|
||||
public:
|
||||
MemBufferBase() : ptr(nullptr), size_in_bytes(0) {}
|
||||
MemBufferBase() noexcept : ptr(nullptr), size_in_bytes(0) {}
|
||||
inline ~MemBufferBase() noexcept {}
|
||||
|
||||
// NOTE: implicit conversion to underlying pointer
|
||||
// HINT: for fully bound-checked pointer use XSPAN_S from xspan.h
|
||||
operator pointer() const { return ptr; }
|
||||
operator pointer() const noexcept { return ptr; }
|
||||
|
||||
// membuffer + n -> pointer
|
||||
template <class U>
|
||||
@ -66,8 +67,8 @@ private:
|
||||
DELETED_FUNCTION;
|
||||
|
||||
public: // raw access
|
||||
pointer raw_ptr() const { return ptr; }
|
||||
size_type raw_size_in_bytes() const { return size_in_bytes; }
|
||||
pointer raw_ptr() const noexcept { return ptr; }
|
||||
size_type raw_size_in_bytes() const noexcept { return size_in_bytes; }
|
||||
|
||||
pointer raw_bytes(size_t bytes) const {
|
||||
if (bytes > 0) {
|
||||
@ -84,7 +85,7 @@ class MemBuffer final : public MemBufferBase<byte> {
|
||||
public:
|
||||
MemBuffer() : MemBufferBase<byte>() {}
|
||||
explicit MemBuffer(upx_uint64_t bytes);
|
||||
~MemBuffer();
|
||||
~MemBuffer() noexcept;
|
||||
|
||||
static unsigned getSizeForCompression(unsigned uncompressed_size, unsigned extra = 0);
|
||||
static unsigned getSizeForDecompression(unsigned uncompressed_size, unsigned extra = 0);
|
||||
@ -93,7 +94,7 @@ public:
|
||||
void allocForCompression(unsigned uncompressed_size, unsigned extra = 0);
|
||||
void allocForDecompression(unsigned uncompressed_size, unsigned extra = 0);
|
||||
|
||||
void dealloc();
|
||||
void dealloc() noexcept;
|
||||
void checkState() const;
|
||||
unsigned getSize() const { return size_in_bytes; }
|
||||
|
||||
|
||||
@ -35,9 +35,11 @@
|
||||
|
||||
// default: for any regular pointer, raw_bytes() is just the pointer itself
|
||||
template <class T>
|
||||
inline
|
||||
typename std::enable_if<std::is_pointer<T>::value && !std_is_bounded_array<T>::value, T>::type
|
||||
raw_bytes(T ptr, size_t size_in_bytes) {
|
||||
inline typename std::enable_if<std::is_pointer<T>::value && !upx_std_is_bounded_array<T>::value &&
|
||||
(upx_is_integral<typename std::remove_pointer<T>::type>::value ||
|
||||
std::is_void<typename std::remove_pointer<T>::type>::value),
|
||||
T>::type
|
||||
raw_bytes(T ptr, size_t size_in_bytes) {
|
||||
if (size_in_bytes > 0) {
|
||||
if very_unlikely (ptr == nullptr)
|
||||
throwCantPack("raw_bytes unexpected NULL ptr");
|
||||
@ -50,9 +52,10 @@ inline
|
||||
// default: for any regular pointer, raw_index_bytes() is just "pointer + index"
|
||||
// NOTE: index == number of elements, *NOT* size in bytes!
|
||||
template <class T>
|
||||
inline
|
||||
typename std::enable_if<std::is_pointer<T>::value && !std_is_bounded_array<T>::value, T>::type
|
||||
raw_index_bytes(T ptr, size_t index, size_t size_in_bytes) {
|
||||
inline typename std::enable_if<std::is_pointer<T>::value && !upx_std_is_bounded_array<T>::value &&
|
||||
upx_is_integral<typename std::remove_pointer<T>::type>::value,
|
||||
T>::type
|
||||
raw_index_bytes(T ptr, size_t index, size_t size_in_bytes) {
|
||||
typedef typename std::remove_pointer<T>::type element_type;
|
||||
if very_unlikely (ptr == nullptr)
|
||||
throwCantPack("raw_index_bytes unexpected NULL ptr");
|
||||
|
||||
@ -60,30 +60,30 @@ upx_rsize_t upx_safe_strlen(const char *);
|
||||
#define vsnprintf upx_safe_vsnprintf
|
||||
|
||||
/*************************************************************************
|
||||
// some unsigned char string support functions to avoid casts
|
||||
// some uchar string support functions to avoid casts
|
||||
**************************************************************************/
|
||||
|
||||
inline unsigned char *strcpy(unsigned char *s1, const unsigned char *s2) {
|
||||
return (unsigned char *) strcpy((char *) s1, (const char *) s2);
|
||||
forceinline uchar *strcpy(uchar *s1, const uchar *s2) {
|
||||
return (uchar *) strcpy((char *) s1, (const char *) s2);
|
||||
}
|
||||
|
||||
inline int strcmp(const unsigned char *s1, const char *s2) { return strcmp((const char *) s1, s2); }
|
||||
inline int strcmp(const char *s1, const unsigned char *s2) { return strcmp(s1, (const char *) s2); }
|
||||
inline int strcmp(const unsigned char *s1, const unsigned char *s2) {
|
||||
forceinline int strcmp(const uchar *s1, const char *s2) { return strcmp((const char *) s1, s2); }
|
||||
forceinline int strcmp(const char *s1, const uchar *s2) { return strcmp(s1, (const char *) s2); }
|
||||
forceinline int strcmp(const uchar *s1, const uchar *s2) {
|
||||
return strcmp((const char *) s1, (const char *) s2);
|
||||
}
|
||||
|
||||
inline int strcasecmp(const unsigned char *s1, const char *s2) {
|
||||
forceinline int strcasecmp(const uchar *s1, const char *s2) {
|
||||
return strcasecmp((const char *) s1, s2);
|
||||
}
|
||||
inline int strcasecmp(const char *s1, const unsigned char *s2) {
|
||||
forceinline int strcasecmp(const char *s1, const uchar *s2) {
|
||||
return strcasecmp(s1, (const char *) s2);
|
||||
}
|
||||
inline int strcasecmp(const unsigned char *s1, const unsigned char *s2) {
|
||||
forceinline int strcasecmp(const uchar *s1, const uchar *s2) {
|
||||
return strcasecmp((const char *) s1, (const char *) s2);
|
||||
}
|
||||
|
||||
inline upx_rsize_t upx_safe_strlen(const unsigned char *s) {
|
||||
forceinline upx_rsize_t upx_safe_strlen(const uchar *s) {
|
||||
return upx_safe_strlen((const char *) s);
|
||||
}
|
||||
|
||||
|
||||
@ -101,6 +101,10 @@ TEST_CASE("mem_size") {
|
||||
CHECK_THROWS(mem_size(1, 0x30000000, 0x30000000, 0x30000000));
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// ptr util
|
||||
**************************************************************************/
|
||||
|
||||
int ptr_diff_bytes(const void *a, const void *b) {
|
||||
if very_unlikely (a == nullptr) {
|
||||
throwCantPack("ptr_diff_bytes null 1; take care");
|
||||
@ -108,13 +112,13 @@ int ptr_diff_bytes(const void *a, const void *b) {
|
||||
if very_unlikely (b == nullptr) {
|
||||
throwCantPack("ptr_diff_bytes null 2; take care");
|
||||
}
|
||||
ptrdiff_t d = (const char *) a - (const char *) b;
|
||||
ptrdiff_t d = (const charptr) a - (const charptr) b;
|
||||
if (a >= b) {
|
||||
if very_unlikely (!mem_size_valid_bytes(d))
|
||||
throwCantPack("ptr_diff_bytes 1; take care");
|
||||
throwCantPack("ptr_diff_bytes-1; take care");
|
||||
} else {
|
||||
if very_unlikely (!mem_size_valid_bytes(-d))
|
||||
throwCantPack("ptr_diff_bytes 2; take care");
|
||||
throwCantPack("ptr_diff_bytes-2; take care");
|
||||
}
|
||||
return ACC_ICONV(int, d);
|
||||
}
|
||||
@ -127,7 +131,7 @@ unsigned ptr_udiff_bytes(const void *a, const void *b) {
|
||||
}
|
||||
|
||||
TEST_CASE("ptr_diff") {
|
||||
char buf[4] = {0, 1, 2, 3};
|
||||
byte buf[4] = {0, 1, 2, 3};
|
||||
CHECK_THROWS(ptr_diff_bytes(nullptr, buf));
|
||||
CHECK_THROWS(ptr_diff_bytes(buf, nullptr));
|
||||
CHECK(ptr_diff(buf, buf) == 0);
|
||||
@ -138,6 +142,108 @@ TEST_CASE("ptr_diff") {
|
||||
CHECK_THROWS(ptr_udiff(buf, buf + 1));
|
||||
}
|
||||
|
||||
// check that 2 buffers do not overlap; will throw on error
|
||||
void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b, size_t b_size) {
|
||||
if very_unlikely (a == 0 || b == 0)
|
||||
throwCantPack("ptr_check_no_overlap-nullptr");
|
||||
upx_uintptr_t a_end = a + mem_size(1, a_size);
|
||||
upx_uintptr_t b_end = b + mem_size(1, b_size);
|
||||
if very_unlikely (a_end < a || b_end < b) // wrap-around
|
||||
throwCantPack("ptr_check_no_overlap-overflow");
|
||||
// same as (!(a >= b_end || b >= a_end))
|
||||
if (a < b_end && b < a_end)
|
||||
throwCantPack("ptr_check_no_overlap-ab");
|
||||
}
|
||||
|
||||
// check that 3 buffers do not overlap; will throw on error
|
||||
void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b, size_t b_size,
|
||||
upx_uintptr_t c, size_t c_size) {
|
||||
if very_unlikely (a == 0 || b == 0 || c == 0)
|
||||
throwCantPack("ptr_check_no_overlap-nullptr");
|
||||
upx_uintptr_t a_end = a + mem_size(1, a_size);
|
||||
upx_uintptr_t b_end = b + mem_size(1, b_size);
|
||||
upx_uintptr_t c_end = c + mem_size(1, c_size);
|
||||
if very_unlikely (a_end < a || b_end < b || c_end < c) // wrap-around
|
||||
throwCantPack("ptr_check_no_overlap-overflow");
|
||||
if (a < b_end && b < a_end)
|
||||
throwCantPack("ptr_check_no_overlap-ab");
|
||||
if (a < c_end && c < a_end)
|
||||
throwCantPack("ptr_check_no_overlap-ac");
|
||||
if (b < c_end && c < b_end)
|
||||
throwCantPack("ptr_check_no_overlap-bc");
|
||||
}
|
||||
|
||||
TEST_CASE("ptr_check_no_overlap 2") {
|
||||
byte p[4] = {};
|
||||
|
||||
auto check_nothrow = [&p](int a, int as, int b, int bs) {
|
||||
CHECK_NOTHROW(ptr_check_no_overlap(p + a, as, p + b, bs)); // ab
|
||||
CHECK_NOTHROW(ptr_check_no_overlap(p + b, bs, p + a, as)); // ba
|
||||
};
|
||||
auto check_throws_ = [&p](int a, int as, int b, int bs) {
|
||||
CHECK_THROWS(ptr_check_no_overlap(p + a, as, p + b, bs)); // ab
|
||||
CHECK_THROWS(ptr_check_no_overlap(p + b, bs, p + a, as)); // ba
|
||||
};
|
||||
|
||||
check_throws_(0, 1, 0, 1);
|
||||
check_nothrow(0, 1, 1, 1);
|
||||
check_throws_(0, 2, 1, 1);
|
||||
check_nothrow(0, 2, 2, 1);
|
||||
// empty buffers at edge
|
||||
check_nothrow(0, 0, 0, 0);
|
||||
check_nothrow(0, 0, 0, 1);
|
||||
check_nothrow(0, 0, 1, 0);
|
||||
// empty buffer
|
||||
check_nothrow(0, 4, 0, 0);
|
||||
check_throws_(0, 4, 1, 0);
|
||||
check_throws_(0, 4, 2, 0);
|
||||
check_throws_(0, 4, 3, 0);
|
||||
check_nothrow(0, 4, 4, 0);
|
||||
}
|
||||
|
||||
TEST_CASE("ptr_check_no_overlap 3") {
|
||||
byte p[4] = {};
|
||||
|
||||
auto check_nothrow = [&p](int a, int as, int b, int bs, int c, int cs) {
|
||||
CHECK_NOTHROW(ptr_check_no_overlap(p + a, as, p + b, bs, p + c, cs)); // abc
|
||||
CHECK_NOTHROW(ptr_check_no_overlap(p + a, as, p + c, cs, p + b, bs)); // acb
|
||||
CHECK_NOTHROW(ptr_check_no_overlap(p + b, bs, p + a, as, p + c, cs)); // bac
|
||||
CHECK_NOTHROW(ptr_check_no_overlap(p + b, bs, p + c, cs, p + a, as)); // bca
|
||||
CHECK_NOTHROW(ptr_check_no_overlap(p + c, cs, p + a, as, p + b, bs)); // cab
|
||||
CHECK_NOTHROW(ptr_check_no_overlap(p + c, cs, p + b, bs, p + a, as)); // cba
|
||||
};
|
||||
auto check_throws_ = [&p](int a, int as, int b, int bs, int c, int cs) {
|
||||
CHECK_THROWS(ptr_check_no_overlap(p + a, as, p + b, bs, p + c, cs)); // abc
|
||||
CHECK_THROWS(ptr_check_no_overlap(p + a, as, p + c, cs, p + b, bs)); // acb
|
||||
CHECK_THROWS(ptr_check_no_overlap(p + b, bs, p + a, as, p + c, cs)); // bac
|
||||
CHECK_THROWS(ptr_check_no_overlap(p + b, bs, p + c, cs, p + a, as)); // bca
|
||||
CHECK_THROWS(ptr_check_no_overlap(p + c, cs, p + a, as, p + b, bs)); // cab
|
||||
CHECK_THROWS(ptr_check_no_overlap(p + c, cs, p + b, bs, p + a, as)); // cba
|
||||
};
|
||||
|
||||
check_throws_(0, 1, 0, 1, 1, 1);
|
||||
check_nothrow(0, 1, 1, 1, 2, 1);
|
||||
check_throws_(0, 2, 1, 1, 2, 1);
|
||||
check_nothrow(0, 2, 2, 1, 3, 1);
|
||||
// empty buffers at edge
|
||||
check_nothrow(0, 0, 0, 0, 0, 0);
|
||||
check_nothrow(0, 0, 0, 0, 0, 1);
|
||||
check_nothrow(0, 0, 0, 1, 1, 1);
|
||||
check_nothrow(0, 0, 1, 0, 1, 1);
|
||||
// empty buffer
|
||||
check_nothrow(0, 4, 0, 0, 0, 0);
|
||||
check_throws_(0, 4, 1, 0, 0, 0);
|
||||
check_throws_(0, 4, 2, 0, 0, 0);
|
||||
check_throws_(0, 4, 3, 0, 0, 0);
|
||||
check_nothrow(0, 4, 4, 0, 0, 0);
|
||||
// empty buffer
|
||||
check_throws_(0, 4, 0, 0, 1, 0);
|
||||
check_throws_(0, 4, 1, 0, 1, 0);
|
||||
check_throws_(0, 4, 2, 0, 1, 0);
|
||||
check_throws_(0, 4, 3, 0, 1, 0);
|
||||
check_throws_(0, 4, 4, 0, 1, 0);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// bele.h
|
||||
**************************************************************************/
|
||||
@ -152,6 +258,60 @@ const BEPolicy be_policy;
|
||||
const LEPolicy le_policy;
|
||||
} // namespace N_BELE_RTP
|
||||
|
||||
/*************************************************************************
|
||||
// stdlib
|
||||
**************************************************************************/
|
||||
|
||||
void *upx_calloc(size_t n, size_t element_size) {
|
||||
size_t bytes = mem_size(element_size, n); // assert size
|
||||
void *p = malloc(bytes);
|
||||
if (p != nullptr)
|
||||
memset(p, 0, bytes);
|
||||
return p;
|
||||
}
|
||||
|
||||
// extremely simple stable sort: Gnomesort
|
||||
// WARNING: O(n**2) !!!!!
|
||||
void upx_stable_sort(void *base, size_t n, size_t element_size,
|
||||
int(__acc_cdecl_qsort *compare)(const void *, const void *)) {
|
||||
(void) mem_size(element_size, n); // assert size
|
||||
for (size_t i = 1; i < n;) {
|
||||
char *a = (char *) base + element_size * i; // a = &array[i]
|
||||
if (i == 0 || (compare(a - element_size, a) <= 0)) {
|
||||
i += 1;
|
||||
} else {
|
||||
i -= 1;
|
||||
// swap elements a[-1] <=> a[0]
|
||||
// upx_memswap(a - element_size, a, element_size);
|
||||
size_t j = element_size;
|
||||
do {
|
||||
char tmp = *(a - element_size);
|
||||
*(a - element_size) = *a;
|
||||
*a++ = tmp;
|
||||
} while (--j != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("upx_stable_sort") {
|
||||
// TODO C++20: use std::next_permutation() to test all permutations
|
||||
{
|
||||
unsigned a[] = {0, 1};
|
||||
upx_stable_sort(a, 2, sizeof(*a), ne32_compare);
|
||||
CHECK((a[0] == 0 && a[1] == 1));
|
||||
}
|
||||
{
|
||||
unsigned a[] = {1, 0};
|
||||
upx_stable_sort(a, 2, sizeof(*a), ne32_compare);
|
||||
CHECK((a[0] == 0 && a[1] == 1));
|
||||
}
|
||||
{
|
||||
unsigned a[] = {2, 1, 0};
|
||||
upx_stable_sort(a, 3, sizeof(*a), ne32_compare);
|
||||
CHECK((a[0] == 0 && a[1] == 1 && a[2] == 2));
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// qsort() util
|
||||
**************************************************************************/
|
||||
@ -258,7 +418,7 @@ int __acc_cdecl_qsort le64_compare_signed(const void *e1, const void *e2) {
|
||||
|
||||
int find(const void *buf, int blen, const void *what, int wlen) {
|
||||
// nullptr is explicitly allowed here
|
||||
if (buf == nullptr || blen <= 0 || what == nullptr || wlen <= 0)
|
||||
if (buf == nullptr || blen < wlen || what == nullptr || wlen <= 0)
|
||||
return -1;
|
||||
|
||||
const byte *b = (const byte *) buf;
|
||||
@ -367,7 +527,7 @@ static const char dir_sep[] = "/\\";
|
||||
#define fn_is_drive(s) (s[0] && s[1] == ':')
|
||||
#define fn_is_sep(c) (strchr(dir_sep, c) != nullptr)
|
||||
#define fn_skip_drive(s) (fn_is_drive(s) ? (s) + 2 : (s))
|
||||
#define fn_tolower(c) (tolower(((unsigned char) (c))))
|
||||
#define fn_tolower(c) (tolower(((uchar) (c))))
|
||||
|
||||
#else
|
||||
|
||||
|
||||
@ -40,9 +40,6 @@ inline bool mem_size_valid_bytes(upx_uint64_t bytes) noexcept { return bytes <=
|
||||
bool mem_size_valid(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1 = 0,
|
||||
upx_uint64_t extra2 = 0) noexcept;
|
||||
|
||||
// "new" with asserted size; will throw on invalid size
|
||||
#define New(type, n) new type[mem_size_get_n(sizeof(type), n)]
|
||||
|
||||
// will throw on invalid size
|
||||
upx_rsize_t mem_size(upx_uint64_t element_size, upx_uint64_t n, upx_uint64_t extra1,
|
||||
upx_uint64_t extra2 = 0);
|
||||
@ -77,6 +74,27 @@ inline void mem_clear(void *p, size_t n) {
|
||||
memset(p, 0, n);
|
||||
}
|
||||
|
||||
// "new" with asserted size; will throw on invalid size
|
||||
#if DEBUG
|
||||
template <class T>
|
||||
T *NewArray(upx_uint64_t n) {
|
||||
size_t bytes = mem_size(sizeof(T), n); // assert size
|
||||
T *array = new T[size_t(n)];
|
||||
if (array) {
|
||||
memset(array, 0xff, bytes);
|
||||
(void) VALGRIND_MAKE_MEM_UNDEFINED(array, bytes);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
#define New(type, n) (NewArray<type>(n))
|
||||
#else
|
||||
#define New(type, n) new type[mem_size_get_n(sizeof(type), n)]
|
||||
#endif
|
||||
|
||||
/*************************************************************************
|
||||
// ptr util
|
||||
**************************************************************************/
|
||||
|
||||
// ptrdiff_t with nullptr checks and asserted size; will throw on failure
|
||||
// NOTE: returns size_in_bytes, not number of elements!
|
||||
int ptr_diff_bytes(const void *a, const void *b);
|
||||
@ -94,6 +112,30 @@ ptr_udiff(const T *a, const U *b) {
|
||||
return ptr_udiff_bytes(a, b);
|
||||
}
|
||||
|
||||
// check that buffers do not overlap; will throw on error
|
||||
noinline void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b,
|
||||
size_t b_size);
|
||||
noinline void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b,
|
||||
size_t b_size, upx_uintptr_t c, size_t c_size);
|
||||
|
||||
forceinline void ptr_check_no_overlap(const void *a, size_t a_size, const void *b, size_t b_size) {
|
||||
uintptr_check_no_overlap((upx_uintptr_t) a, a_size, (upx_uintptr_t) b, b_size);
|
||||
}
|
||||
forceinline void ptr_check_no_overlap(const void *a, size_t a_size, const void *b, size_t b_size,
|
||||
const void *c, size_t c_size) {
|
||||
uintptr_check_no_overlap((upx_uintptr_t) a, a_size, (upx_uintptr_t) b, b_size,
|
||||
(upx_uintptr_t) c, c_size);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
// stdlib
|
||||
**************************************************************************/
|
||||
|
||||
void *upx_calloc(size_t n, size_t element_size);
|
||||
|
||||
void upx_stable_sort(void *base, size_t n, size_t element_size,
|
||||
int(__acc_cdecl_qsort *compare)(const void *, const void *));
|
||||
|
||||
/*************************************************************************
|
||||
// misc. support functions
|
||||
**************************************************************************/
|
||||
|
||||
@ -44,28 +44,28 @@ struct XSpanStats {
|
||||
static XSpanStats xspan_stats;
|
||||
|
||||
// HINT: set env-var "UPX_DEBUG_DOCTEST_DISABLE=1" for improved debugging experience
|
||||
noinline void xspan_fail_nullptr() {
|
||||
void xspan_fail_nullptr() {
|
||||
xspan_stats.fail_nullptr += 1;
|
||||
throwCantPack("xspan unexpected NULL pointer; take care!");
|
||||
}
|
||||
noinline void xspan_fail_nullbase() {
|
||||
void xspan_fail_nullbase() {
|
||||
xspan_stats.fail_nullbase += 1;
|
||||
throwCantPack("xspan unexpected NULL base; take care!");
|
||||
}
|
||||
noinline void xspan_fail_not_same_base() {
|
||||
void xspan_fail_not_same_base() {
|
||||
xspan_stats.fail_not_same_base += 1;
|
||||
throwCantPack("xspan unexpected base pointer; take care!");
|
||||
}
|
||||
|
||||
noinline void xspan_fail_range_nullptr() {
|
||||
void xspan_fail_range_nullptr() {
|
||||
xspan_stats.fail_range_nullptr += 1;
|
||||
throwCantPack("xspan_check_range: unexpected NULL pointer; take care!");
|
||||
}
|
||||
noinline void xspan_fail_range_nullbase() {
|
||||
void xspan_fail_range_nullbase() {
|
||||
xspan_stats.fail_range_nullbase += 1;
|
||||
throwCantPack("xspan_check_range: unexpected NULL base; take care!");
|
||||
}
|
||||
noinline void xspan_fail_range_range() {
|
||||
void xspan_fail_range_range() {
|
||||
xspan_stats.fail_range_range += 1;
|
||||
throwCantPack("xspan_check_range: pointer out of range; take care!");
|
||||
}
|
||||
@ -75,7 +75,7 @@ void xspan_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes)
|
||||
xspan_fail_range_nullptr();
|
||||
if very_unlikely (base == nullptr)
|
||||
xspan_fail_range_nullbase();
|
||||
ptrdiff_t off = (const char *) p - (const char *) base;
|
||||
ptrdiff_t off = (const charptr) p - (const charptr) base;
|
||||
if very_unlikely (off < 0 || off > size_in_bytes)
|
||||
xspan_fail_range_range();
|
||||
xspan_stats.check_range_counter += 1;
|
||||
|
||||
@ -146,8 +146,11 @@ inline R *xspan_make_helper__(R * /*dummy*/, MemBuffer &first) {
|
||||
|
||||
#endif // WITH_XSPAN
|
||||
|
||||
#if 1
|
||||
/*************************************************************************
|
||||
// nicer names
|
||||
**************************************************************************/
|
||||
|
||||
#if 1
|
||||
#define SPAN_0 XSPAN_0
|
||||
#define SPAN_P XSPAN_P
|
||||
#define SPAN_S XSPAN_S
|
||||
|
||||
@ -52,11 +52,11 @@ void xspan_check_range(const void *p, const void *base, ptrdiff_t size_in_bytes)
|
||||
|
||||
// help constructor to distinguish between number of elements and bytes
|
||||
struct XSpanCount {
|
||||
explicit XSpanCount(size_t n) : count(n) {}
|
||||
explicit XSpanCount(size_t n) noexcept : count(n) {}
|
||||
size_t count; // public
|
||||
};
|
||||
struct XSpanSizeInBytes {
|
||||
explicit XSpanSizeInBytes(size_t bytes) : size_in_bytes(bytes) {}
|
||||
explicit XSpanSizeInBytes(size_t bytes) noexcept : size_in_bytes(bytes) {}
|
||||
size_t size_in_bytes; // public
|
||||
};
|
||||
|
||||
|
||||
@ -28,165 +28,176 @@
|
||||
//
|
||||
**************************************************************************/
|
||||
|
||||
public:
|
||||
typedef T element_type;
|
||||
typedef typename std::add_lvalue_reference<T>::type reference;
|
||||
typedef typename std::add_pointer<T>::type pointer;
|
||||
typedef size_t size_type;
|
||||
#if CLANG_FORMAT_DUMMY_CLASS
|
||||
class CSelf {
|
||||
#endif
|
||||
|
||||
// befriend all
|
||||
template <class>
|
||||
friend struct PtrOrSpan;
|
||||
template <class>
|
||||
friend struct PtrOrSpanOrNull;
|
||||
template <class>
|
||||
friend struct Span;
|
||||
public:
|
||||
typedef T element_type;
|
||||
typedef typename std::add_lvalue_reference<T>::type reference;
|
||||
typedef typename std::add_pointer<T>::type pointer;
|
||||
typedef size_t size_type;
|
||||
|
||||
// befriend all
|
||||
template <class>
|
||||
friend struct PtrOrSpan;
|
||||
template <class>
|
||||
friend struct PtrOrSpanOrNull;
|
||||
template <class>
|
||||
friend struct Span;
|
||||
|
||||
#if XSPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION
|
||||
operator pointer() const { return ptr; }
|
||||
public:
|
||||
operator pointer() const noexcept { return ptr; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
pointer ptr; // current view into (base, base+size_in_bytes) iff base != nullptr
|
||||
pointer base;
|
||||
size_type size_in_bytes;
|
||||
pointer ptr; // current view into (base, base+size_in_bytes) iff base != nullptr
|
||||
pointer base;
|
||||
size_type size_in_bytes;
|
||||
|
||||
// debug - internal sanity check; also serves as pseudo-documentation
|
||||
#if DEBUG
|
||||
noinline void assertInvariants() const {
|
||||
noinline void assertInvariants() const {
|
||||
if __acc_cte (configRequirePtr)
|
||||
assert(ptr != nullptr);
|
||||
if __acc_cte (configRequireBase)
|
||||
assert(base != nullptr);
|
||||
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
|
||||
if __acc_cte ((configRequirePtr || ptr != nullptr) &&
|
||||
(configRequireBase || base != nullptr))
|
||||
xspan_check_range(ptr, base, size_in_bytes);
|
||||
}
|
||||
}
|
||||
#else
|
||||
forceinline void assertInvariants() const {}
|
||||
inline void assertInvariants() const noexcept {}
|
||||
#endif
|
||||
|
||||
static forceinline pointer makeNotNull(pointer p) {
|
||||
static inline pointer makeNotNull(pointer p) {
|
||||
if very_unlikely (p == nullptr)
|
||||
xspan_fail_nullptr();
|
||||
return p;
|
||||
}
|
||||
// enforce config invariants at constructor time - static functions
|
||||
static forceinline pointer makePtr(pointer p) {
|
||||
}
|
||||
// enforce config invariants at constructor time - static functions
|
||||
static inline pointer makePtr(pointer p) {
|
||||
if __acc_cte (configRequirePtr && p == nullptr)
|
||||
xspan_fail_nullptr();
|
||||
return p;
|
||||
}
|
||||
static forceinline pointer makeBase(pointer b) {
|
||||
}
|
||||
static inline pointer makeBase(pointer b) {
|
||||
if __acc_cte (configRequireBase && b == nullptr)
|
||||
xspan_fail_nullbase();
|
||||
return b;
|
||||
}
|
||||
// inverse logic for ensuring valid pointers from existing objets
|
||||
forceinline pointer ensurePtr() const {
|
||||
}
|
||||
// inverse logic for ensuring valid pointers from existing objects
|
||||
inline pointer ensurePtr() const {
|
||||
if __acc_cte (!configRequirePtr && ptr == nullptr)
|
||||
xspan_fail_nullptr();
|
||||
return ptr;
|
||||
}
|
||||
forceinline pointer ensureBase() const {
|
||||
}
|
||||
inline pointer ensureBase() const {
|
||||
if __acc_cte (!configRequireBase && base == nullptr)
|
||||
xspan_fail_nullbase();
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
inline ~CSelf() {
|
||||
#if DEBUG
|
||||
invalidate();
|
||||
inline ~CSelf() { invalidate(); }
|
||||
#else
|
||||
inline ~CSelf() noexcept {}
|
||||
#endif
|
||||
}
|
||||
noinline void invalidate() {
|
||||
noinline void invalidate() {
|
||||
assertInvariants();
|
||||
ptr = (pointer) (acc_uintptr_t) 16; // point to non-null invalid address
|
||||
ptr = (pointer) (upx_uintptr_t) 16; // point to non-null invalid address
|
||||
// ptr = (pointer) (void *) &ptr; // point to self
|
||||
base = ptr;
|
||||
size_in_bytes = 0;
|
||||
assertInvariants();
|
||||
}
|
||||
// constructors from pointers
|
||||
CSelf(pointer first, XSpanCount count)
|
||||
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(xspan_mem_size<T>(count.count)) {
|
||||
}
|
||||
// constructors from pointers
|
||||
CSelf(pointer first, XSpanCount count)
|
||||
: ptr(makePtr(first)), base(makeBase(first)),
|
||||
size_in_bytes(xspan_mem_size<T>(count.count)) {
|
||||
assertInvariants();
|
||||
}
|
||||
CSelf(pointer first, XSpanSizeInBytes bytes)
|
||||
}
|
||||
CSelf(pointer first, XSpanSizeInBytes bytes)
|
||||
: ptr(makePtr(first)), base(makeBase(first)),
|
||||
size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) {
|
||||
assertInvariants();
|
||||
}
|
||||
// enable this constructor only if the underlying type is char or void
|
||||
template <class U>
|
||||
CSelf(U *first, size_type count, XSPAN_REQUIRES_SIZE_1_A)
|
||||
}
|
||||
// enable this constructor only if the underlying type is char or void
|
||||
template <class U>
|
||||
CSelf(U *first, size_type count, XSPAN_REQUIRES_SIZE_1_A)
|
||||
: ptr(makePtr(first)), base(makeBase(first)), size_in_bytes(xspan_mem_size<T>(count)) {
|
||||
assertInvariants();
|
||||
}
|
||||
CSelf(pointer first, XSpanCount count, pointer base_)
|
||||
: ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(xspan_mem_size<T>(count.count)) {
|
||||
}
|
||||
CSelf(pointer first, XSpanCount count, pointer base_)
|
||||
: ptr(makePtr(first)), base(makeBase(base_)),
|
||||
size_in_bytes(xspan_mem_size<T>(count.count)) {
|
||||
// check invariants
|
||||
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
|
||||
if __acc_cte ((configRequirePtr || ptr != nullptr) &&
|
||||
(configRequireBase || base != nullptr))
|
||||
xspan_check_range(ptr, base, size_in_bytes);
|
||||
// double sanity check
|
||||
assertInvariants();
|
||||
}
|
||||
CSelf(pointer first, XSpanSizeInBytes bytes, pointer base_)
|
||||
}
|
||||
CSelf(pointer first, XSpanSizeInBytes bytes, pointer base_)
|
||||
: ptr(makePtr(first)), base(makeBase(base_)),
|
||||
size_in_bytes(xspan_mem_size<char>(bytes.size_in_bytes)) {
|
||||
// check invariants
|
||||
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
|
||||
if __acc_cte ((configRequirePtr || ptr != nullptr) &&
|
||||
(configRequireBase || base != nullptr))
|
||||
xspan_check_range(ptr, base, size_in_bytes);
|
||||
// double sanity check
|
||||
assertInvariants();
|
||||
}
|
||||
// enable this constructor only if the underlying type is char or void
|
||||
template <class U>
|
||||
CSelf(pointer first, size_type count, U *base_, XSPAN_REQUIRES_SIZE_1_A)
|
||||
}
|
||||
// enable this constructor only if the underlying type is char or void
|
||||
template <class U>
|
||||
CSelf(pointer first, size_type count, U *base_, XSPAN_REQUIRES_SIZE_1_A)
|
||||
: ptr(makePtr(first)), base(makeBase(base_)), size_in_bytes(xspan_mem_size<T>(count)) {
|
||||
// check invariants
|
||||
if __acc_cte ((configRequirePtr || ptr != nullptr) && (configRequireBase || base != nullptr))
|
||||
if __acc_cte ((configRequirePtr || ptr != nullptr) &&
|
||||
(configRequireBase || base != nullptr))
|
||||
xspan_check_range(ptr, base, size_in_bytes);
|
||||
// double sanity check
|
||||
assertInvariants();
|
||||
}
|
||||
}
|
||||
#ifdef UPX_VERSION_HEX
|
||||
// constructors from MemBuffer
|
||||
CSelf(MemBuffer &mb)
|
||||
// constructors from MemBuffer
|
||||
CSelf(MemBuffer &mb)
|
||||
: CSelf(makeNotNull((pointer) membuffer_get_void_ptr(mb)),
|
||||
XSpanSizeInBytes(membuffer_get_size(mb))) {}
|
||||
CSelf(pointer first, MemBuffer &mb)
|
||||
CSelf(pointer first, MemBuffer &mb)
|
||||
: CSelf(first, XSpanSizeInBytes(membuffer_get_size(mb)),
|
||||
makeNotNull((pointer) membuffer_get_void_ptr(mb))) {}
|
||||
CSelf(std::nullptr_t, MemBuffer &) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, MemBuffer &) XSPAN_DELETED_FUNCTION;
|
||||
#endif
|
||||
// disable constructors from nullptr to catch compile-time misuse
|
||||
// disable constructors from nullptr to catch compile-time misuse
|
||||
private:
|
||||
CSelf(std::nullptr_t, XSpanCount) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(const void *, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, XSpanSizeInBytes) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(const void *, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, size_type) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(const void *, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, XSpanCount) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(const void *, XSpanCount, std::nullptr_t) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, XSpanSizeInBytes) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(const void *, XSpanSizeInBytes, std::nullptr_t) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, size_type) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(std::nullptr_t, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION;
|
||||
CSelf(const void *, size_type, std::nullptr_t) XSPAN_DELETED_FUNCTION;
|
||||
|
||||
// unchecked constructor
|
||||
// unchecked constructor
|
||||
protected:
|
||||
enum ModeUnchecked { Unchecked };
|
||||
CSelf(ModeUnchecked, pointer p, size_type bytes, pointer b)
|
||||
enum ModeUnchecked { Unchecked };
|
||||
CSelf(ModeUnchecked, pointer p, size_type bytes, pointer b)
|
||||
: ptr(p), base(b), size_in_bytes(bytes) {
|
||||
assertInvariants();
|
||||
}
|
||||
// unchecked assignment
|
||||
Self &assign(ModeUnchecked, pointer p, size_type bytes, pointer b) {
|
||||
}
|
||||
// unchecked assignment
|
||||
Self &assign(ModeUnchecked, pointer p, size_type bytes, pointer b) {
|
||||
ptr = p;
|
||||
base = b;
|
||||
size_in_bytes = bytes;
|
||||
assertInvariants();
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
Self &assign(ModeUnchecked, const Self &other) {
|
||||
ptr = other.ptr;
|
||||
@ -198,19 +209,20 @@ Self &assign(ModeUnchecked, const Self &other) {
|
||||
#endif
|
||||
|
||||
public:
|
||||
// assignment - here we can rely on invariants enforced at construction time by makePtr/makeBase
|
||||
// NOTE: *this remains unmodified in case of failure
|
||||
Self &assign(pointer other) {
|
||||
// assignment - here we can rely on invariants enforced at construction time by makePtr/makeBase
|
||||
// NOTE: *this remains unmodified in case of failure
|
||||
Self &assign(pointer other) {
|
||||
assertInvariants();
|
||||
other = makePtr(other);
|
||||
if __acc_cte ((configRequirePtr || other != nullptr) && (configRequireBase || base != nullptr))
|
||||
if __acc_cte ((configRequirePtr || other != nullptr) &&
|
||||
(configRequireBase || base != nullptr))
|
||||
xspan_check_range(other, base, size_in_bytes);
|
||||
// ok
|
||||
ptr = other;
|
||||
assertInvariants();
|
||||
return *this;
|
||||
}
|
||||
Self &assign(const Self &other) {
|
||||
}
|
||||
Self &assign(const Self &other) {
|
||||
assertInvariants();
|
||||
other.assertInvariants();
|
||||
if __acc_cte (!configRequireBase && base == nullptr) {
|
||||
@ -235,154 +247,154 @@ Self &assign(const Self &other) {
|
||||
}
|
||||
assertInvariants();
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
Self &operator=(pointer other) { return assign(other); }
|
||||
Self &operator=(pointer other) { return assign(other); }
|
||||
|
||||
Self &operator=(const Self &other) { return assign(other); }
|
||||
Self &operator=(const Self &other) { return assign(other); }
|
||||
|
||||
// FIXME: this is not called??
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(Self &)
|
||||
operator=(const CSelf<U> &other) {
|
||||
// FIXME: this is not called??
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(Self &)
|
||||
operator=(const CSelf<U> &other) {
|
||||
// assert(0);
|
||||
return assign(Self(other));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UPX_VERSION_HEX
|
||||
Self &operator=(MemBuffer &mb) { return assign(Self(mb)); }
|
||||
Self &operator=(MemBuffer &mb) { return assign(Self(mb)); }
|
||||
#endif
|
||||
|
||||
Self subspan(ptrdiff_t offset, ptrdiff_t count) {
|
||||
Self subspan(ptrdiff_t offset, ptrdiff_t count) {
|
||||
pointer begin = check_add(ptr, offset);
|
||||
pointer end = check_add(begin, count);
|
||||
if (begin <= end)
|
||||
return Self(Unchecked, begin, (end - begin) * sizeof(T), begin);
|
||||
else
|
||||
return Self(Unchecked, end, (begin - end) * sizeof(T), end);
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(pointer other) const { return ptr == other; }
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator==(U *other) const {
|
||||
bool operator==(pointer other) const { return ptr == other; }
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator==(U *other) const {
|
||||
return ptr == other;
|
||||
}
|
||||
bool operator!=(pointer other) const { return ptr != other; }
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator!=(U *other) const {
|
||||
}
|
||||
bool operator!=(pointer other) const { return ptr != other; }
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator!=(U *other) const {
|
||||
return ptr != other;
|
||||
}
|
||||
}
|
||||
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator==(const PtrOrSpan<U> &other) const {
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator==(const PtrOrSpan<U> &other) const {
|
||||
return ptr == other.ptr;
|
||||
}
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator==(const PtrOrSpanOrNull<U> &other) const {
|
||||
}
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator==(const PtrOrSpanOrNull<U> &other) const {
|
||||
return ptr == other.ptr;
|
||||
}
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator==(const Span<U> &other) const {
|
||||
}
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator==(const Span<U> &other) const {
|
||||
return ptr == other.ptr;
|
||||
}
|
||||
}
|
||||
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator!=(const PtrOrSpan<U> &other) const {
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator!=(const PtrOrSpan<U> &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator!=(const PtrOrSpanOrNull<U> &other) const {
|
||||
}
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator!=(const PtrOrSpanOrNull<U> &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator!=(const Span<U> &other) const {
|
||||
}
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator!=(const Span<U> &other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
}
|
||||
|
||||
// check for notNull here
|
||||
bool operator<(std::nullptr_t) const XSPAN_DELETED_FUNCTION;
|
||||
bool operator<(pointer other) const { return ensurePtr() < makeNotNull(other); }
|
||||
// check for notNull here
|
||||
bool operator<(std::nullptr_t) const XSPAN_DELETED_FUNCTION;
|
||||
bool operator<(pointer other) const { return ensurePtr() < makeNotNull(other); }
|
||||
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator<(const PtrOrSpan<U> &other) const {
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator<(const PtrOrSpan<U> &other) const {
|
||||
return ensurePtr() < other.ensurePtr();
|
||||
}
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator<(const PtrOrSpanOrNull<U> &other) const {
|
||||
}
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator<(const PtrOrSpanOrNull<U> &other) const {
|
||||
return ensurePtr() < other.ensurePtr();
|
||||
}
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator<(const Span<U> &other) const {
|
||||
}
|
||||
template <class U>
|
||||
XSPAN_REQUIRES_CONVERTIBLE_R(bool)
|
||||
operator<(const Span<U> &other) const {
|
||||
return ensurePtr() < other.ensurePtr();
|
||||
}
|
||||
}
|
||||
|
||||
// dereference
|
||||
reference operator*() const { return *check_deref(ptr); }
|
||||
// dereference
|
||||
reference operator*() const { return *check_deref(ptr); }
|
||||
|
||||
// array access
|
||||
reference operator[](ptrdiff_t i) const { return *check_deref(ptr, i); }
|
||||
// array access
|
||||
reference operator[](ptrdiff_t i) const { return *check_deref(ptr, i); }
|
||||
|
||||
// arrow operator
|
||||
pointer operator->() const { return check_deref(ptr); }
|
||||
// arrow operator
|
||||
pointer operator->() const { return check_deref(ptr); }
|
||||
|
||||
Self &operator++() {
|
||||
Self &operator++() {
|
||||
ptr = check_add(ptr, 1);
|
||||
return *this;
|
||||
}
|
||||
Self operator++(int) {
|
||||
}
|
||||
Self operator++(int) {
|
||||
Self tmp = *this;
|
||||
++*this;
|
||||
return tmp;
|
||||
}
|
||||
Self &operator--() {
|
||||
}
|
||||
Self &operator--() {
|
||||
ptr = check_add(ptr, -1);
|
||||
return *this;
|
||||
}
|
||||
Self operator--(int) {
|
||||
}
|
||||
Self operator--(int) {
|
||||
Self tmp = *this;
|
||||
--*this;
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
Self &operator+=(ptrdiff_t n) {
|
||||
Self &operator+=(ptrdiff_t n) {
|
||||
ptr = check_add(ptr, n);
|
||||
return *this;
|
||||
}
|
||||
Self &operator-=(ptrdiff_t n) {
|
||||
}
|
||||
Self &operator-=(ptrdiff_t n) {
|
||||
ptr = check_add(ptr, -n);
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
Self operator+(ptrdiff_t n) const {
|
||||
Self operator+(ptrdiff_t n) const {
|
||||
pointer first = check_add(ptr, n);
|
||||
return Self(Unchecked, first, size_in_bytes, base);
|
||||
}
|
||||
Self operator-(ptrdiff_t n) const {
|
||||
}
|
||||
Self operator-(ptrdiff_t n) const {
|
||||
pointer first = check_add(ptr, -n);
|
||||
return Self(Unchecked, first, size_in_bytes, base);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
pointer check_deref(pointer p) const {
|
||||
pointer check_deref(pointer p) const {
|
||||
if __acc_cte (!configRequirePtr && p == nullptr)
|
||||
xspan_fail_nullptr();
|
||||
if __acc_cte (configRequireBase || base != nullptr)
|
||||
xspan_check_range(p, base, size_in_bytes - sizeof(T));
|
||||
assertInvariants();
|
||||
return p;
|
||||
}
|
||||
pointer check_deref(pointer p, ptrdiff_t n) const {
|
||||
}
|
||||
pointer check_deref(pointer p, ptrdiff_t n) const {
|
||||
if __acc_cte (!configRequirePtr && p == nullptr)
|
||||
xspan_fail_nullptr();
|
||||
xspan_mem_size_assert_ptrdiff<T>(n);
|
||||
@ -391,8 +403,8 @@ pointer check_deref(pointer p, ptrdiff_t n) const {
|
||||
xspan_check_range(p, base, size_in_bytes - sizeof(T));
|
||||
assertInvariants();
|
||||
return p;
|
||||
}
|
||||
pointer check_add(pointer p, ptrdiff_t n) const {
|
||||
}
|
||||
pointer check_add(pointer p, ptrdiff_t n) const {
|
||||
if __acc_cte (!configRequirePtr && p == nullptr)
|
||||
xspan_fail_nullptr();
|
||||
xspan_mem_size_assert_ptrdiff<T>(n);
|
||||
@ -401,18 +413,18 @@ pointer check_add(pointer p, ptrdiff_t n) const {
|
||||
xspan_check_range(p, base, size_in_bytes);
|
||||
assertInvariants();
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
// 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]
|
||||
Self *operator&() const XSPAN_DELETED_FUNCTION;
|
||||
// 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]
|
||||
Self *operator&() const XSPAN_DELETED_FUNCTION;
|
||||
|
||||
public: // raw access
|
||||
pointer raw_ptr() const { return ptr; }
|
||||
pointer raw_base() const { return base; }
|
||||
size_type raw_size_in_bytes() const { return size_in_bytes; }
|
||||
pointer raw_ptr() const noexcept { return ptr; }
|
||||
pointer raw_base() const noexcept { return base; }
|
||||
size_type raw_size_in_bytes() const noexcept { return size_in_bytes; }
|
||||
|
||||
pointer raw_bytes(size_t bytes) const {
|
||||
pointer raw_bytes(size_t bytes) const {
|
||||
assertInvariants();
|
||||
if (bytes > 0) {
|
||||
if __acc_cte (!configRequirePtr && ptr == nullptr)
|
||||
@ -422,6 +434,25 @@ pointer raw_bytes(size_t bytes) const {
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
// like C++ std::span
|
||||
pointer data() const noexcept { return ptr; }
|
||||
pointer data(size_t bytes) const { return raw_bytes(bytes); } // UPX extra
|
||||
// size_type size() const { return size_bytes() / sizeof(element_type); } // NOT USED
|
||||
size_type size_bytes() const {
|
||||
assertInvariants();
|
||||
if __acc_cte (!configRequirePtr && ptr == nullptr)
|
||||
return 0;
|
||||
if __acc_cte (!configRequireBase && base == nullptr)
|
||||
return 0;
|
||||
const charptr begin = (const charptr) ptr;
|
||||
const charptr end = (const charptr) base + size_in_bytes;
|
||||
return end - begin;
|
||||
}
|
||||
|
||||
#if CLANG_FORMAT_DUMMY_CLASS
|
||||
}; // class
|
||||
#endif
|
||||
|
||||
/* vim:set ts=4 sw=4 et: */
|
||||
|
||||
@ -51,25 +51,25 @@ private:
|
||||
pointer ptr;
|
||||
|
||||
// enforce config invariants at constructor time - static functions
|
||||
static forceinline pointer makePtr(pointer p) { return p; }
|
||||
// inverse logic for ensuring valid pointers from existing objets
|
||||
forceinline pointer ensurePtr() const { return ptr; }
|
||||
static inline pointer makePtr(pointer p) { return p; }
|
||||
// inverse logic for ensuring valid pointers from existing objects
|
||||
inline pointer ensurePtr() const { return ptr; }
|
||||
// debug
|
||||
forceinline void assertInvariants() const {}
|
||||
inline void assertInvariants() const noexcept {}
|
||||
|
||||
public:
|
||||
#if XSPAN_CONFIG_ENABLE_IMPLICIT_CONVERSION || 1
|
||||
operator pointer() const { return ptr; }
|
||||
operator pointer() const noexcept { return ptr; }
|
||||
#endif
|
||||
|
||||
inline ~CSelf() {
|
||||
#if DEBUG
|
||||
invalidate();
|
||||
inline ~CSelf() { invalidate(); }
|
||||
#else
|
||||
inline ~CSelf() noexcept {}
|
||||
#endif
|
||||
}
|
||||
noinline void invalidate() {
|
||||
assertInvariants();
|
||||
ptr = (pointer) (acc_uintptr_t) 16; // point to non-null invalid address
|
||||
ptr = (pointer) (upx_uintptr_t) 16; // point to non-null invalid address
|
||||
// ptr = (pointer) (void *) &ptr; // point to self
|
||||
assertInvariants();
|
||||
}
|
||||
@ -116,7 +116,7 @@ public:
|
||||
return assign(Self(other));
|
||||
}
|
||||
|
||||
// comparision
|
||||
// comparison
|
||||
|
||||
bool operator==(pointer other) const { return ptr == other; }
|
||||
template <class U>
|
||||
@ -187,7 +187,7 @@ private:
|
||||
forceinline pointer check_add(pointer p, ptrdiff_t n) const { return p + n; }
|
||||
|
||||
public: // raw access
|
||||
pointer raw_ptr() const { return ptr; }
|
||||
pointer raw_ptr() const noexcept { return ptr; }
|
||||
|
||||
pointer raw_bytes(size_t bytes) const {
|
||||
assertInvariants();
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
*/
|
||||
|
||||
// This file implements the central loop, and it uses class PackMaster to
|
||||
// dispatch. PackMaster by itself will instatiate a concrete subclass
|
||||
// dispatch. PackMaster by itself will instantiate a concrete subclass
|
||||
// of class Packer which then does the actual work.
|
||||
// And see p_com.cpp for a simple executable format.
|
||||
|
||||
@ -141,7 +141,7 @@ void do_one_file(const char *iname, char *oname) {
|
||||
else
|
||||
flags |= O_EXCL;
|
||||
int shmode = SH_DENYWR;
|
||||
#if defined(__MINT__)
|
||||
#if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__)
|
||||
flags |= O_TRUNC;
|
||||
shmode = O_DENYRW;
|
||||
#endif
|
||||
@ -266,7 +266,7 @@ static void unlink_ofile(char *oname) {
|
||||
int do_files(int i, int argc, char *argv[]) {
|
||||
upx_compiler_sanity_check();
|
||||
if (opt->verbose >= 1) {
|
||||
show_head();
|
||||
show_header();
|
||||
UiPacker::uiHeader();
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user