1
0
mirror of https://github.com/upx/upx synced 2025-09-28 19:06:07 +08:00

Merge branch 'devel' into devel4

This commit is contained in:
Markus F.X.J. Oberhumer 2023-03-18 21:52:17 +01:00
commit f68ac8155b
28 changed files with 351 additions and 287 deletions

11
.github/CODEOWNERS vendored Normal file
View File

@ -0,0 +1,11 @@
* @markus-oberhumer @jreiser
/src/p_elf* @jreiser
/src/p_lx_* @jreiser
/src/p_mach* @jreiser
/src/p_unix* @jreiser
/src/p_vmlin* @jreiser
/src/stub/src/*bsd.* @jreiser
/src/stub/src/*darwin.* @jreiser
/src/stub/src/*linux.* @jreiser

View File

@ -9,6 +9,7 @@ extend-exclude = ["LICENSE"]
[default.extend-identifiers] [default.extend-identifiers]
# misc variable names & symbols # misc variable names & symbols
acc_spawnve = "acc_spawnve" acc_spawnve = "acc_spawnve"
ba = "ba"
fo = "fo" fo = "fo"
fof = "fof" fof = "fof"
sidelen = "sidelen" sidelen = "sidelen"

View File

@ -377,8 +377,8 @@ jobs:
- { zig_target: x86_64-macos.13-none } - { zig_target: x86_64-macos.13-none }
- { zig_target: x86_64-windows-gnu } - { zig_target: x86_64-windows-gnu }
env: env:
# 2023-03-14 # 2023-03-18
ZIG_DIST_VERSION: 0.11.0-dev.1970+962299157 ZIG_DIST_VERSION: 0.11.0-dev.2157+f56f3c582
# for zig-cc wrapper scripts (see below): # for zig-cc wrapper scripts (see below):
ZIG_CPPFLAGS: -DUPX_DOCTEST_CONFIG_MULTITHREADING ZIG_CPPFLAGS: -DUPX_DOCTEST_CONFIG_MULTITHREADING
ZIG_FLAGS: ${{ matrix.zig_flags }} ZIG_FLAGS: ${{ matrix.zig_flags }}

View File

@ -5,22 +5,25 @@ name: 'CI - Minimal CI with Alpine Linux'
on: [workflow_dispatch] on: [workflow_dispatch]
jobs: jobs:
job-alpine-cmake: job-alpine-cmake:
strategy: {matrix: {container: ['alpine:3.12','alpine:3.17','alpine:edge']}} strategy:
fail-fast: false
matrix: {container: ['alpine:3.12','alpine:3.17','alpine:edge','i386/alpine:edge']}
name: ${{ format('container {0}', matrix.container) }} name: ${{ format('container {0}', matrix.container) }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: ${{ matrix.container }} container: ${{ matrix.container }}
steps: steps:
- name: ${{ format('Install packages {0}', matrix.container) }} - name: ${{ format('Install packages {0}', matrix.container) }}
run: 'apk update && apk upgrade && apk add bash clang cmake g++ git make' run: 'apk update && apk upgrade && apk add bash clang cmake g++ git make'
- name: ${{ format('Check out code upx-{0}', github.ref_name) }} - name: ${{ format('Check out UPX {0} source code', github.ref_name) }}
run: | run: |
git clone --branch "$GITHUB_REF_NAME" --depth 1 https://github.com/upx/upx git clone --branch "$GITHUB_REF_NAME" --depth 1 https://github.com/upx/upx
git -C upx submodule update --init git -C upx submodule update --init
echo "artifact_name=upx-${GITHUB_REF_NAME}-${GITHUB_SHA:0:7}-minimal-ci-${{ matrix.container }}" | sed 's/[:,; ]/-/g' >> $GITHUB_ENV echo "artifact_name=upx-${GITHUB_REF_NAME}-${GITHUB_SHA:0:7}-minimal-ci-${{ matrix.container }}" | sed 's/[^=0-9a-zA-Z_.-]/-/g' >> $GITHUB_ENV
- { name: 'Build clang', run: 'make -C upx UPX_XTARGET=clang-static CC="clang -static" CXX="clang++ -static"' } - { name: 'Build clang', run: 'make -C upx UPX_XTARGET=clang-static CC="clang -static" CXX="clang++ -static"' }
- { name: 'Build gcc', run: 'make -C upx UPX_XTARGET=gcc-static CC="gcc -static" CXX="g++ -static"' } - { name: 'Build gcc', run: 'make -C upx UPX_XTARGET=gcc-static CC="gcc -static" CXX="g++ -static"' }
- { name: 'Strip release binaries', run: 'strip -p --strip-unneeded upx/build/*/*/release/upx' } - { name: 'Strip release binaries', run: 'strip -p --strip-unneeded upx/build/*/*/release/upx' }
- name: ${{ format('Upload artifact {0}', env.artifact_name) }} - name: ${{ format('Upload artifact {0}', env.artifact_name) }}
if: ${{ !startsWith(matrix.container, 'i386/alpine') }} # missing nodejs
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: ${{ env.artifact_name }} name: ${{ env.artifact_name }}

View File

@ -7,16 +7,20 @@ on:
jobs: jobs:
analyze: analyze:
name: Analyze strategy:
fail-fast: false
matrix: {container: ['alpine:3.16','alpine:3.17','alpine:edge','i386/alpine:edge']}
name: ${{ format('Analyze {0}', matrix.container) }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: 'alpine:edge' container: ${{ matrix.container }}
steps: steps:
- name: 'Install packages' - name: ${{ format('Install packages {0}', matrix.container) }}
run: 'apk update && apk upgrade && apk add bash clang clang-analyzer cmake g++ git make' run: 'apk update && apk upgrade && apk add bash clang clang-analyzer cmake g++ git make'
- name: 'Check out code' - name: ${{ format('Check out UPX {0} source code', github.ref_name) }}
uses: actions/checkout@v3 run: |
with: { submodules: true } git clone --branch "$GITHUB_REF_NAME" --depth 1 https://github.com/upx/upx
git -C upx submodule update --init
- name: 'Perform scan-build Analysis Debug' - name: 'Perform scan-build Analysis Debug'
run: 'make build/extra/scan-build/debug' run: 'make -C upx build/extra/scan-build/debug'
- name: 'Perform scan-build Analysis Release' - name: 'Perform scan-build Analysis Release'
run: 'make build/extra/scan-build/release' run: 'make -C upx build/extra/scan-build/release'

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR) # CMake >= 3.20.0 is recommended cmake_minimum_required(VERSION 3.8.0 FATAL_ERROR) # CMake >= 3.20 is recommended
# compilation config options # compilation config options
if(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git") if(NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git")
@ -331,7 +331,7 @@ endif()
if(CMAKE_INSTALL_PREFIX AND DEFINED CMAKE_INSTALL_FULL_BINDIR) if(CMAKE_INSTALL_PREFIX AND DEFINED CMAKE_INSTALL_FULL_BINDIR)
install(TARGETS upx DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}") install(TARGETS upx DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}")
install(FILES install(FILES
COPYING LICENSE NEWS README THANKS doc/upx-doc.html doc/upx-doc.txt COPYING LICENSE NEWS README doc/THANKS.txt doc/upx-doc.html doc/upx-doc.txt
DESTINATION "${CMAKE_INSTALL_FULL_DOCDIR}" DESTINATION "${CMAKE_INSTALL_FULL_DOCDIR}"
) )
install(FILES doc/upx.1 DESTINATION "${CMAKE_INSTALL_FULL_MANDIR}/man1") install(FILES doc/upx.1 DESTINATION "${CMAKE_INSTALL_FULL_MANDIR}/man1")

View File

@ -683,6 +683,9 @@ typedef BE64 NE64;
#define ne16_compare be16_compare #define ne16_compare be16_compare
#define ne32_compare be32_compare #define ne32_compare be32_compare
#define ne64_compare be64_compare #define ne64_compare be64_compare
#define ne16_compare_signed be16_compare_signed
#define ne32_compare_signed be32_compare_signed
#define ne64_compare_signed be64_compare_signed
#else #else
typedef LE16 NE16; typedef LE16 NE16;
typedef LE32 NE32; typedef LE32 NE32;
@ -690,6 +693,9 @@ typedef LE64 NE64;
#define ne16_compare le16_compare #define ne16_compare le16_compare
#define ne32_compare le32_compare #define ne32_compare le32_compare
#define ne64_compare le64_compare #define ne64_compare le64_compare
#define ne16_compare_signed le16_compare_signed
#define ne32_compare_signed le32_compare_signed
#define ne64_compare_signed le64_compare_signed
#endif #endif
/************************************************************************* /*************************************************************************

View File

@ -26,43 +26,14 @@
*/ */
#pragma once #pragma once
#ifndef UPX_CONF_H__
#define UPX_CONF_H__ 1
#if !(__cplusplus+0 >= 201703L)
# error "C++ 17 is required"
#endif
#include "version.h"
#if !defined(_FILE_OFFSET_BITS)
# define _FILE_OFFSET_BITS 64
#endif
#if defined(_WIN32) && defined(__MINGW32__) && defined(__GNUC__)
# if !defined(_USE_MINGW_ANSI_STDIO)
# define _USE_MINGW_ANSI_STDIO 1
# endif
#endif
/************************************************************************* /*************************************************************************
// ACC and system includes // init
**************************************************************************/ **************************************************************************/
#ifndef ACC_CFG_USE_NEW_STYLE_CASTS #include "headers.h"
#define ACC_CFG_USE_NEW_STYLE_CASTS 1 #include "version.h"
#endif
#define ACC_CFG_PREFER_TYPEOF_ACC_INT32E_T ACC_TYPEOF_INT
#define ACC_CFG_PREFER_TYPEOF_ACC_INT64E_T ACC_TYPEOF_LONG_LONG
#include "miniacc.h"
#if !(ACC_CC_CLANG || ACC_CC_GNUC || ACC_CC_MSC)
// other compilers may work, but we're NOT interested into supporting them
# error "only clang, gcc and msvc are officially supported"
#endif
// UPX sanity checks for a sane compiler
#if !defined(UINT_MAX) || (UINT_MAX != 0xffffffffL)
# error "UINT_MAX"
#endif
ACC_COMPILE_TIME_ASSERT_HEADER(CHAR_BIT == 8) ACC_COMPILE_TIME_ASSERT_HEADER(CHAR_BIT == 8)
ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(short) == 2) ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(short) == 2)
ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(int) == 4) ACC_COMPILE_TIME_ASSERT_HEADER(sizeof(int) == 4)
@ -101,43 +72,10 @@ ACC_COMPILE_TIME_ASSERT_HEADER((char)(-1) == 255) // -funsigned-char
#endif #endif
#endif // !UPX_CONFIG_DISABLE_WSTRICT && !UPX_CONFIG_DISABLE_WERROR #endif // !UPX_CONFIG_DISABLE_WSTRICT && !UPX_CONFIG_DISABLE_WERROR
// disable some warnings
#if (ACC_CC_MSC)
# pragma warning(disable: 4244) // -Wconversion
# pragma warning(disable: 4267) // -Wconversion
# pragma warning(disable: 4820) // padding added after data member
#endif
#undef snprintf
#undef vsnprintf
#define HAVE_STDINT_H 1
#define ACC_WANT_ACC_INCD_H 1
#define ACC_WANT_ACC_INCE_H 1
#define ACC_WANT_ACC_LIB_H 1
#define ACC_WANT_ACC_CXX_H 1
#include "miniacc.h"
#if (ACC_CC_MSC)
# include <intrin.h>
#endif
// C++ system headers
#include <exception>
#include <new>
#include <type_traits>
#include <typeinfo>
// multithreading (UPX currently does not use multithreading) // 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) #if (WITH_THREADS)
#define upx_thread_local thread_local #define upx_thread_local thread_local
#include <atomic>
#define upx_std_atomic(Type) std::atomic<Type> #define upx_std_atomic(Type) std::atomic<Type>
#include <mutex>
#define upx_std_once_flag std::once_flag #define upx_std_once_flag std::once_flag
#define upx_std_call_once std::call_once #define upx_std_call_once std::call_once
#else #else
@ -150,29 +88,6 @@ inline void upx_std_call_once(upx_std_once_flag &flag, NoexceptCallable &&f) {
} }
#endif // WITH_THREADS #endif // WITH_THREADS
// C++ submodule headers
#include <doctest/doctest/parts/doctest_fwd.h>
#if WITH_BOOST_PFR
# include <sstream>
# include <boost/pfr/io.hpp>
#endif
#if WITH_RANGELESS_FN
# include <rangeless/include/fn.hpp>
#endif
#ifndef WITH_VALGRIND
# define WITH_VALGRIND 1
#endif
#if defined(__SANITIZE_ADDRESS__) || defined(_WIN32) || !defined(__GNUC__)
# undef WITH_VALGRIND
#endif
#if (WITH_VALGRIND)
# include <valgrind/include/valgrind/memcheck.h>
#endif
// IMPORTANT: unconditionally enable assertions
#undef NDEBUG
#include <assert.h>
// <type_traits> C++20 std::is_bounded_array // <type_traits> C++20 std::is_bounded_array
template <class T> template <class T>
struct upx_std_is_bounded_array : public std::false_type {}; struct upx_std_is_bounded_array : public std::false_type {};
@ -195,7 +110,6 @@ inline constexpr bool upx_is_integral_v = upx_is_integral<T>::value;
#define alignas(x) upx_fake_alignas__(x) #define alignas(x) upx_fake_alignas__(x)
#endif #endif
/************************************************************************* /*************************************************************************
// core // core
**************************************************************************/ **************************************************************************/
@ -922,12 +836,4 @@ int upx_test_overlap ( const upx_bytep buf,
#include "util/xspan.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>"
# endif
#endif
#endif /* already included */
/* vim:set ts=4 sw=4 et: */ /* vim:set ts=4 sw=4 et: */

View File

@ -67,8 +67,8 @@ f80_jcc2(Filter const *f)
// Adaptively remember recent destinations. // Adaptively remember recent destinations.
static void static void
update_mru( update_mru(
unsigned const jc, // destination address const unsigned jc, // destination address
int const kh, // mru[kh] is slot where found const int kh, // mru[kh] is slot where found
unsigned mru[N_MRU], // circular buffer of most recent destinations unsigned mru[N_MRU], // circular buffer of most recent destinations
int &hand, // mru[hand] is most recent destination int &hand, // mru[hand] is most recent destination
int &tail // mru[tail] is beyond oldest destination ("cold cache" startup) int &tail // mru[tail] is beyond oldest destination ("cold cache" startup)
@ -77,7 +77,7 @@ update_mru(
if (0 > --hand) { if (0 > --hand) {
hand = N_MRU -1; hand = N_MRU -1;
} }
unsigned const t = mru[hand]; // entry which will be overwritten by jc const unsigned t = mru[hand]; // entry which will be overwritten by jc
if (0!=t) { // have seen at least N_MRU destinations if (0!=t) { // have seen at least N_MRU destinations
mru[kh] = t; mru[kh] = t;
} }
@ -85,7 +85,7 @@ update_mru(
if (0 > --tail) { if (0 > --tail) {
tail = N_MRU -1; tail = N_MRU -1;
} }
unsigned const t2 = mru[tail]; const unsigned t2 = mru[tail];
mru[tail] = 0; mru[tail] = 0;
mru[kh] = t2; mru[kh] = t2;
} }
@ -111,9 +111,9 @@ static int F(Filter *f)
unsigned wtally[3]; memset(wtally, 0, sizeof(wtally)); unsigned wtally[3]; memset(wtally, 0, sizeof(wtally));
#ifdef U //{ #ifdef U //{
unsigned const f_call = f80_call(f); const unsigned f_call = f80_call(f);
unsigned const f_jmp1 = f80_jmp1(f); const unsigned f_jmp1 = f80_jmp1(f);
unsigned const f_jcc2 = f80_jcc2(f); const unsigned f_jcc2 = f80_jcc2(f);
int hand = 0, tail = 0; int hand = 0, tail = 0;
unsigned mru[N_MRU]; unsigned mru[N_MRU];
@ -273,9 +273,9 @@ static int U(Filter *f)
const unsigned cto = (unsigned)f->cto << 24; const unsigned cto = (unsigned)f->cto << 24;
unsigned lastcall = 0; unsigned lastcall = 0;
int hand = 0, tail = 0; int hand = 0, tail = 0;
unsigned const f_call = f80_call(f); const unsigned f_call = f80_call(f);
unsigned const f_jmp1 = f80_jmp1(f); const unsigned f_jmp1 = f80_jmp1(f);
unsigned const f_jcc2 = f80_jcc2(f); const unsigned f_jcc2 = f80_jcc2(f);
unsigned mru[N_MRU]; unsigned mru[N_MRU];
memset(&mru[0], 0, sizeof(mru)); memset(&mru[0], 0, sizeof(mru));

View File

@ -46,7 +46,7 @@ static int F(Filter *f)
#endif #endif
const unsigned addvalue = f->addvalue; const unsigned addvalue = f->addvalue;
const unsigned size = f->buf_len; const unsigned size = f->buf_len;
unsigned const id = f->id; const unsigned id = f->id;
unsigned ic, jc, kc; unsigned ic, jc, kc;
unsigned calls = 0, noncalls = 0, noncalls2 = 0; unsigned calls = 0, noncalls = 0, noncalls2 = 0;
@ -145,7 +145,7 @@ static int U(Filter *f)
const unsigned size5 = f->buf_len - 5; const unsigned size5 = f->buf_len - 5;
const unsigned addvalue = f->addvalue; const unsigned addvalue = f->addvalue;
const unsigned cto = (unsigned)f->cto << 24; const unsigned cto = (unsigned)f->cto << 24;
unsigned const id = f->id; const unsigned id = f->id;
unsigned lastcall = 0; unsigned lastcall = 0;
unsigned ic, jc; unsigned ic, jc;

View File

@ -30,7 +30,7 @@
#include "../filter.h" #include "../filter.h"
static unsigned static unsigned
umin(unsigned const a, unsigned const b) umin(const unsigned a, const unsigned b)
{ {
return (a<=b) ? a : b; return (a<=b) ? a : b;
} }

116
src/headers.h Normal file
View File

@ -0,0 +1,116 @@
/* headers.h -- include system headers
This file is part of the UPX executable compressor.
Copyright (C) 1996-2023 Markus Franz Xaver Johannes Oberhumer
All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer
<markus@oberhumer.com>
*/
#pragma once
#if !(__cplusplus + 0 >= 201703L)
#error "C++ 17 is required"
#endif
#if !defined(_FILE_OFFSET_BITS)
#define _FILE_OFFSET_BITS 64
#endif
#if defined(_WIN32) && defined(__MINGW32__) && defined(__GNUC__)
#if !defined(_USE_MINGW_ANSI_STDIO)
#define _USE_MINGW_ANSI_STDIO 1
#endif
#endif
// ACC and C system headers
#ifndef ACC_CFG_USE_NEW_STYLE_CASTS
#define ACC_CFG_USE_NEW_STYLE_CASTS 1
#endif
#define ACC_CFG_PREFER_TYPEOF_ACC_INT32E_T ACC_TYPEOF_INT
#define ACC_CFG_PREFER_TYPEOF_ACC_INT64E_T ACC_TYPEOF_LONG_LONG
#include "miniacc.h"
// disable some pedantic warnings
#if (ACC_CC_MSC)
#pragma warning(disable : 4244) // -Wconversion
#pragma warning(disable : 4267) // -Wconversion
#pragma warning(disable : 4820) // padding added after data member
#endif
#undef snprintf
#undef vsnprintf
#define HAVE_STDINT_H 1
#define ACC_WANT_ACC_INCD_H 1
#define ACC_WANT_ACC_INCE_H 1
#define ACC_WANT_ACC_LIB_H 1
#define ACC_WANT_ACC_CXX_H 1
#include "miniacc.h"
#if (ACC_CC_MSC)
#include <intrin.h>
#endif
// C++ system headers
#include <exception>
#include <new>
#include <type_traits>
// C++ 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
#include <atomic>
#include <mutex>
#endif
// C++ submodule headers
#include <doctest/doctest/parts/doctest_fwd.h>
#if WITH_BOOST_PFR
#include <sstream>
#include <boost/pfr/io.hpp>
#endif
#if WITH_RANGELESS_FN
#include <rangeless/include/fn.hpp>
#endif
#ifndef WITH_VALGRIND
#define WITH_VALGRIND 1
#endif
#if defined(__SANITIZE_ADDRESS__) || defined(_WIN32) || !defined(__GNUC__)
#undef WITH_VALGRIND
#endif
#if WITH_VALGRIND
#include <valgrind/include/valgrind/memcheck.h>
#endif
// IMPORTANT: unconditionally enable assertions
#undef NDEBUG
#include <assert.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>"
#endif
#endif
/* vim:set ts=4 sw=4 et: */

View File

@ -49,13 +49,13 @@ protected:
struct alignas(1) le_header_t { struct alignas(1) le_header_t {
// 0x00 // 0x00
char _[2]; // signature: 'LE' || 'LX' byte _[2]; // signature: 'LE' || 'LX'
char byte_order; // 0 little endian byte byte_order; // 0 little endian
char word_order; // 0 little endian byte word_order; // 0 little endian
LE32 exe_format_level; // 0 LE32 exe_format_level; // 0
LE16 cpu_type; // 1->286..4->586 LE16 cpu_type; // 1->286..4->586
LE16 target_os; // 1->OS2 LE16 target_os; // 1->OS2
char _0[4]; // module_version = 0 byte _0[4]; // module_version = 0
// 0x10 // 0x10
LE32 module_type; // 0x200->compatible with PM windowing LE32 module_type; // 0x200->compatible with PM windowing
LE32 memory_pages; LE32 memory_pages;
@ -68,21 +68,21 @@ protected:
LE32 bytes_on_last_page; LE32 bytes_on_last_page;
// 0x30 // 0x30
LE32 fixup_size; LE32 fixup_size;
char _1[4]; // fixup_checksum = 0 byte _1[4]; // fixup_checksum = 0
LE32 loader_size; LE32 loader_size;
char _2[4]; // loader_checksum = 0 byte _2[4]; // loader_checksum = 0
// 0x40 // 0x40
LE32 object_table_offset; LE32 object_table_offset;
LE32 object_table_entries; LE32 object_table_entries;
LE32 object_pagemap_offset; LE32 object_pagemap_offset;
LE32 object_iterate_data_map_offset; LE32 object_iterate_data_map_offset;
// 0x50 // 0x50
char _3[4]; // resource_offset byte _3[4]; // resource_offset
LE32 resource_entries; LE32 resource_entries;
LE32 resident_names_offset; LE32 resident_names_offset;
LE32 entry_table_offset; LE32 entry_table_offset;
// 0x60 // 0x60
char _4[4]; // module_directives_table_offset = 0 byte _4[4]; // module_directives_table_offset = 0
LE32 module_directives_entries; LE32 module_directives_entries;
LE32 fixup_page_table_offset; LE32 fixup_page_table_offset;
LE32 fixup_record_table_offset; LE32 fixup_record_table_offset;
@ -90,17 +90,17 @@ protected:
LE32 imported_modules_name_table_offset; LE32 imported_modules_name_table_offset;
LE32 imported_modules_count; LE32 imported_modules_count;
LE32 imported_procedures_name_table_offset; LE32 imported_procedures_name_table_offset;
char _5[4]; // per_page_checksum_table_offset = 0 byte _5[4]; // per_page_checksum_table_offset = 0
// 0x80 // 0x80
LE32 data_pages_offset; LE32 data_pages_offset;
char _6[4]; // preload_page_count = 0 byte _6[4]; // preload_page_count = 0
LE32 non_resident_name_table_offset; LE32 non_resident_name_table_offset;
LE32 non_resident_name_table_length; LE32 non_resident_name_table_length;
// 0x90 // 0x90
char _7[4]; // non_resident_names_checksum byte _7[4]; // non_resident_names_checksum
LE32 automatic_data_object; LE32 automatic_data_object;
#if 1 #if 1
char _8[44]; byte _8[44];
#else #else
LE32 debug_info_offset; LE32 debug_info_offset;
LE32 debug_info_length; LE32 debug_info_length;
@ -108,7 +108,7 @@ protected:
LE32 preload_instance_pages; LE32 preload_instance_pages;
LE32 demand_instance_pages; LE32 demand_instance_pages;
LE32 extra_heap_alloc; LE32 extra_heap_alloc;
char reserved[12]; byte reserved[12];
LE32 versioninfo; LE32 versioninfo;
LE32 unknown; LE32 unknown;
// 0xC0 // 0xC0

View File

@ -406,8 +406,8 @@ int ElfLinker::addLoader(const char *sname) {
assert(tail); assert(tail);
assert(tail != section); assert(tail != section);
// .p2align must be < 32 // .p2align must be < 32
unsigned const v = ~0u << section->p2align; const unsigned v = ~0u << section->p2align;
if (unsigned const l = ~v & (0u - (unsigned) (tail->offset + tail->size))) { if (const unsigned l = ~v & (0u - (unsigned) (tail->offset + tail->size))) {
alignCode(l); alignCode(l);
tail->size += l; tail->size += l;
} }

View File

@ -25,6 +25,8 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#include "headers.h"
#include <typeinfo>
#include "conf.h" #include "conf.h"
/************************************************************************* /*************************************************************************

View File

@ -65,32 +65,32 @@ protected:
unsigned coff_offset; unsigned coff_offset;
struct alignas(1) external_scnhdr_t { struct alignas(1) external_scnhdr_t {
char _[12]; // name, paddr byte _[12]; // name, paddr
LE32 vaddr; LE32 vaddr;
LE32 size; LE32 size;
LE32 scnptr; LE32 scnptr;
char misc[12]; // relptr, lnnoptr, nreloc, nlnno byte misc[12]; // relptr, lnnoptr, nreloc, nlnno
char __[4]; // flags byte __[4]; // flags
}; };
struct alignas(1) coff_header_t { struct alignas(1) coff_header_t {
// ext_file_hdr // ext_file_hdr
LE16 f_magic; LE16 f_magic;
LE16 f_nscns; LE16 f_nscns;
char _[4]; // f_timdat byte _[4]; // f_timdat
LE32 f_symptr; LE32 f_symptr;
LE32 f_nsyms; LE32 f_nsyms;
char __[2]; // f_opthdr byte __[2]; // f_opthdr
LE16 f_flags; LE16 f_flags;
// aout_hdr // aout_hdr
LE16 a_magic; LE16 a_magic;
char ___[2]; // a_vstamp byte ___[2]; // a_vstamp
LE32 a_tsize; LE32 a_tsize;
LE32 a_dsize; LE32 a_dsize;
char ____[4]; // a_bsize byte ____[4]; // a_bsize
LE32 a_entry; LE32 a_entry;
char _____[8]; // a_text_start a_data_start byte _____[8]; // a_text_start a_data_start
// section headers // section headers
external_scnhdr_t sh[3]; external_scnhdr_t sh[3];

View File

@ -80,11 +80,11 @@ protected:
LE16 max; LE16 max;
LE16 ss; LE16 ss;
LE16 sp; LE16 sp;
char _[2]; // checksum byte _[2]; // checksum
LE16 ip; LE16 ip;
LE16 cs; LE16 cs;
LE16 relocoffs; LE16 relocoffs;
char __[2]; // overlnum byte __[2]; // overlnum
LE32 firstreloc; LE32 firstreloc;
}; };

View File

@ -68,7 +68,7 @@ protected:
struct alignas(1) ps1_exe_t { struct alignas(1) ps1_exe_t {
// ident string // ident string
char id[8]; byte id[8];
// is nullptr // is nullptr
LE32 text; LE32 text;
// is nullptr // is nullptr
@ -86,7 +86,7 @@ protected:
// saved regs on execution // saved regs on execution
LE32 sp, fp, gp0, ra, k0; LE32 sp, fp, gp0, ra, k0;
// origin Jap/USA/Europe // origin Jap/USA/Europe
char origin[60]; byte origin[60];
// backup of the original header (epc - is_len) // backup of the original header (epc - is_len)
// id & the upx header ... // id & the upx header ...
}; };

View File

@ -65,11 +65,11 @@ protected:
int big_relocs = 0; int big_relocs = 0;
struct alignas(1) tmt_header_t { struct alignas(1) tmt_header_t {
char _[16]; // signature,linkerversion,minversion,exesize,imagestart byte _[16]; // signature,linkerversion,minversion,exesize,imagestart
LE32 imagesize; LE32 imagesize;
char __[4]; // initial memory byte __[4]; // initial memory
LE32 entry; LE32 entry;
char ___[12]; // esp,numfixups,flags byte ___[12]; // esp,numfixups,flags
LE32 relocsize; LE32 relocsize;
}; };
tmt_header_t ih, oh; tmt_header_t ih, oh;

View File

@ -527,7 +527,7 @@ void PackWcle::decodeFixups() {
SPAN_S_VAR(const byte, p, oimage + soimage); SPAN_S_VAR(const byte, p, oimage + soimage);
MemBuffer mb_relocs; MemBuffer mb_relocs;
unsigned const fixupn = unoptimizeReloc(p, mb_relocs, oimage, soimage, 32, true); const unsigned fixupn = unoptimizeReloc(p, mb_relocs, oimage, soimage, 32, true);
MemBuffer wrkmem(8 * fixupn + 8); MemBuffer wrkmem(8 * fixupn + 8);
unsigned ic, jc, o, r; unsigned ic, jc, o, r;

View File

@ -1092,13 +1092,13 @@ done:
} }
void Packer::compressWithFilters(byte *i_ptr, void Packer::compressWithFilters(byte *i_ptr,
unsigned const i_len, // written and restored by filters const unsigned i_len, // written and restored by filters
byte *const o_ptr, // where to put compressed output byte *const o_ptr, // where to put compressed output
byte *f_ptr, byte *f_ptr,
unsigned const f_len, // subset of [*i_ptr, +i_len) const unsigned f_len, // subset of [*i_ptr, +i_len)
byte *const hdr_ptr, unsigned const hdr_len, byte *const hdr_ptr, const unsigned hdr_len,
Filter *const parm_ft, // updated Filter *const parm_ft, // updated
unsigned const overlap_range, const unsigned overlap_range,
upx_compress_config_t const *const cconf, upx_compress_config_t const *const cconf,
int filter_strategy, // in+out for prepareFilters int filter_strategy, // in+out for prepareFilters
bool const inhibit_compression_check) { bool const inhibit_compression_check) {

View File

@ -91,11 +91,11 @@ void Packer::addFilter32(int filter_id) {
} }
if (0x80 == (filter_id & 0xF0)) { if (0x80 == (filter_id & 0xF0)) {
bool const x386 = (opt->cpu <= opt->CPU_386); bool const x386 = (opt->cpu <= opt->CPU_386);
unsigned const n_mru = ph.n_mru ? 1 + ph.n_mru : 0; const unsigned n_mru = ph.n_mru ? 1 + ph.n_mru : 0;
bool const mrupwr2 = (0 != n_mru) && 0 == ((n_mru - 1) & n_mru); bool const mrupwr2 = (0 != n_mru) && 0 == ((n_mru - 1) & n_mru);
unsigned const f_call = f80_call(filter_id); const unsigned f_call = f80_call(filter_id);
unsigned const f_jmp1 = f80_jmp1(filter_id); const unsigned f_jmp1 = f80_jmp1(filter_id);
unsigned const f_jcc2 = f80_jcc2(filter_id); const unsigned f_jcc2 = f80_jcc2(filter_id);
if (NOFILT != f_jcc2) { if (NOFILT != f_jcc2) {
addLoader("LXJCC010"); addLoader("LXJCC010");
@ -296,9 +296,9 @@ void Packer::defineFilterSymbols(const Filter *ft) {
#if 0 #if 0
if (0x80 == (ft->id & 0xF0)) { if (0x80 == (ft->id & 0xF0)) {
int const mru = ph.n_mru ? 1 + ph.n_mru : 0; const int mru = ph.n_mru ? 1 + ph.n_mru : 0;
if (mru && mru != 256) { if (mru && mru != 256) {
unsigned const is_pwr2 = (0 == ((mru - 1) & mru)); const unsigned is_pwr2 = (0 == ((mru - 1) & mru));
// patch_le32(0x80 + (char *) loader, lsize - 0x80, "NMRU", mru - is_pwr2); // patch_le32(0x80 + (char *) loader, lsize - 0x80, "NMRU", mru - is_pwr2);
} }
} }

View File

@ -178,7 +178,7 @@ int PeFile::readFileHeader() {
(unsigned) h.nexepos, (unsigned) sizeof(exe_header_t)); (unsigned) h.nexepos, (unsigned) sizeof(exe_header_t));
throwCantPack(buf); throwCantPack(buf);
} }
unsigned const delta = (h.relocoffs >= 0x40) const unsigned delta = (h.relocoffs >= 0x40)
? h.nexepos // new format exe ? h.nexepos // new format exe
: (h.p512 * 512 + h.m512 - h.m512 ? 512 : h.nexepos); : (h.p512 * 512 + h.m512 - h.m512 ? 512 : h.nexepos);
@ -367,8 +367,8 @@ void PeFile32::processRelocs() // pass1
{ {
big_relocs = 0; big_relocs = 0;
unsigned const take1 = IDSIZE(PEDIR_RELOC); const unsigned skip1 = IDADDR(PEDIR_RELOC);
unsigned const skip1 = IDADDR(PEDIR_RELOC); const unsigned take1 = IDSIZE(PEDIR_RELOC);
Reloc rel(ibuf.subref("bad reloc %#x", skip1, take1), take1); Reloc rel(ibuf.subref("bad reloc %#x", skip1, take1), take1);
const unsigned *counts = rel.getcounts(); const unsigned *counts = rel.getcounts();
unsigned relocnum = 0; unsigned relocnum = 0;
@ -465,8 +465,8 @@ void PeFile64::processRelocs() // pass1
{ {
big_relocs = 0; big_relocs = 0;
unsigned const take = IDSIZE(PEDIR_RELOC); const unsigned skip = IDADDR(PEDIR_RELOC);
unsigned const skip = IDADDR(PEDIR_RELOC); const unsigned take = IDSIZE(PEDIR_RELOC);
Reloc rel(ibuf.subref("bad reloc %#x", skip, take), take); Reloc rel(ibuf.subref("bad reloc %#x", skip, take), take);
const unsigned *counts = rel.getcounts(); const unsigned *counts = rel.getcounts();
unsigned relocnum = 0; unsigned relocnum = 0;
@ -598,15 +598,13 @@ class PeFile::ImportLinker final : public ElfLinkerAMD64 {
// encoding of dll and proc names are required, so that our special // encoding of dll and proc names are required, so that our special
// control characters in the name of sections can work as intended // control characters in the name of sections can work as intended
static char *encode_name(const char *name, char *buf) { static void encode_name(const char *name, char *buf) {
char *b = buf;
while (*name) { while (*name) {
*b++ = 'a' + ((*name >> 4) & 0xf); *buf++ = 'a' + ((*name >> 4) & 0xf);
*b++ = 'a' + (*name & 0xf); *buf++ = 'a' + (*name & 0xf);
name++; name++;
} }
*b = 0; *buf = 0;
return buf;
} }
static char *name_for_dll(const char *dll, char first_char) { static char *name_for_dll(const char *dll, char first_char) {
@ -615,13 +613,13 @@ class PeFile::ImportLinker final : public ElfLinkerAMD64 {
assert(l > 0); assert(l > 0);
char *name = New(char, 3 * l + 2); char *name = New(char, 3 * l + 2);
assert(name);
name[0] = first_char; name[0] = first_char;
char *n = name + 1 + 2 * l; char *n = name + 1 + 2 * l;
do { do {
*n++ = tolower(*dll); *n++ = tolower((uchar) *dll);
} while (*dll++); } while (*dll++);
return encode_name(name + 1 + 2 * l, name + 1) - 1; encode_name(name + 1 + 2 * l, name + 1);
return name;
} }
static char *name_for_proc(const char *dll, const char *proc, char first_char, char separator) { static char *name_for_proc(const char *dll, const char *proc, char first_char, char separator) {
@ -696,7 +694,10 @@ class PeFile::ImportLinker final : public ElfLinkerAMD64 {
static int __acc_cdecl_qsort compare(const void *p1, const void *p2) { static int __acc_cdecl_qsort compare(const void *p1, const void *p2) {
const Section *s1 = *(const Section *const *) p1; const Section *s1 = *(const Section *const *) p1;
const Section *s2 = *(const Section *const *) p2; const Section *s2 = *(const Section *const *) p2;
return strcmp(s1->name, s2->name); int rc = strcmp(s1->name, s2->name);
if (rc != 0)
return rc;
return s1 < s2 ? -1 : 1; // make sort order deterministic/stable
} }
virtual void alignCode(unsigned len) override { alignWithByte(len, 0); } virtual void alignCode(unsigned len) override { alignWithByte(len, 0); }
@ -841,26 +842,26 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
} }
unsigned dllnum = 0; unsigned dllnum = 0;
unsigned const take = IDSIZE(PEDIR_IMPORT); const unsigned skip = IDADDR(PEDIR_IMPORT);
unsigned const skip = IDADDR(PEDIR_IMPORT); const unsigned take = IDSIZE(PEDIR_IMPORT);
import_desc *im = (import_desc *) ibuf.subref("bad import %#x", skip, take); import_desc *const im_start = (import_desc *) ibuf.subref("bad import %#x", skip, take);
import_desc *const im_save = im; if (IDADDR(PEDIR_IMPORT) != 0) {
if (IDADDR(PEDIR_IMPORT)) { for (const import_desc *im = im_start;; ++dllnum, ++im) {
for (;; ++dllnum, ++im) { const unsigned skip2 = ptr_udiff_bytes(im, ibuf);
unsigned const skip2 = ptr_udiff_bytes(im, ibuf);
(void) ibuf.subref("bad import %#x", skip2, sizeof(*im)); (void) ibuf.subref("bad import %#x", skip2, sizeof(*im));
if (!im->dllname) if (im->dllname == 0)
break; break;
} }
im = im_save;
} }
if (dllnum > 4096) // just some arbitrary limit/sanity check
throwCantPack("too many DLL imports %u", dllnum);
struct udll { struct udll {
const byte *name; const byte *name;
const byte *shname; const byte *shname;
unsigned ordinal; unsigned ordinal;
unsigned iat; unsigned iat;
LEXX *lookupt; const LEXX *lookupt;
unsigned original_position; unsigned original_position;
bool isk32; bool isk32;
@ -872,16 +873,20 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
if ((*u1->lookupt != 0) != (*u2->lookupt != 0)) if ((*u1->lookupt != 0) != (*u2->lookupt != 0))
return (*u1->lookupt != 0) ? -1 : 1; return (*u1->lookupt != 0) ? -1 : 1;
int rc = strcasecmp(u1->name, u2->name); int rc = strcasecmp(u1->name, u2->name);
if (rc) if (rc != 0)
return rc; return rc;
if ((u1->ordinal != 0) != (u2->ordinal != 0)) if ((u1->ordinal != 0) != (u2->ordinal != 0))
return (u1->ordinal != 0) ? -1 : 1; return (u1->ordinal != 0) ? -1 : 1;
if ((u1->shname != nullptr) != (u2->shname != nullptr)) if (u1->shname && u2->shname) {
rc = (int) (upx_safe_strlen(u1->shname) - upx_safe_strlen(u2->shname));
if (rc != 0)
return rc;
rc = strcmp(u1->shname, u2->shname);
if (rc != 0)
return rc;
} else if ((u1->shname != nullptr) != (u2->shname != nullptr))
return (u1->shname != nullptr) ? -1 : 1; return (u1->shname != nullptr) ? -1 : 1;
rc = (int) (upx_safe_strlen(u1->shname) - upx_safe_strlen(u2->shname)); return u1 < u2 ? -1 : 1; // make sort order deterministic/stable
if (rc)
return rc;
return strcmp(u1->shname, u2->shname);
} }
}; };
@ -891,14 +896,14 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
soimport = 1024; // safety soimport = 1024; // safety
unsigned ic; for (unsigned ic = 0; ic < dllnum; ic++) {
for (ic = 0; dllnum && im->dllname; ic++, im++) { const import_desc *const im = im_start + ic;
idlls[ic] = dlls + ic; idlls[ic] = dlls + ic;
dlls[ic].name = ibuf.subref("bad dllname %#x", im->dllname, 1); dlls[ic].name = ibuf.subref("bad dllname %#x", im->dllname, 1);
dlls[ic].shname = nullptr; dlls[ic].shname = nullptr;
dlls[ic].ordinal = 0; dlls[ic].ordinal = 0;
dlls[ic].iat = im->iat; dlls[ic].iat = im->iat;
unsigned const skip2 = (im->oft ? im->oft : im->iat); const unsigned skip2 = (im->oft ? im->oft : im->iat);
dlls[ic].lookupt = (LEXX *) ibuf.subref("bad dll lookupt %#x", skip2, sizeof(LEXX)); dlls[ic].lookupt = (LEXX *) ibuf.subref("bad dll lookupt %#x", skip2, sizeof(LEXX));
dlls[ic].original_position = ic; dlls[ic].original_position = ic;
dlls[ic].isk32 = strcasecmp(kernelDll(), dlls[ic].name) == 0; dlls[ic].isk32 = strcasecmp(kernelDll(), dlls[ic].name) == 0;
@ -912,11 +917,11 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
dlls[ic].ordinal = *tarr & 0xffff; dlls[ic].ordinal = *tarr & 0xffff;
} else { } else {
// it's an import by name // it's an import by name
IPTR_VAR(const byte, const name, ibuf + *tarr + 2); IPTR_VAR(const byte, const name, ibuf + (*tarr + 2));
unsigned len = strlen(name); unsigned len = strlen(name);
soimport += len + 1; soimport += len + 1;
if (dlls[ic].shname == nullptr || len < strlen(dlls[ic].shname)) if (dlls[ic].shname == nullptr || len < strlen(dlls[ic].shname))
dlls[ic].shname = ibuf + *tarr + 2; dlls[ic].shname = ibuf + (*tarr + 2);
} }
soimport++; // separator soimport++; // separator
} }
@ -928,7 +933,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
qsort(idlls, dllnum, sizeof(*idlls), udll::compare); qsort(idlls, dllnum, sizeof(*idlls), udll::compare);
info("Processing imports: %d DLLs", dllnum); info("Processing imports: %d DLLs", dllnum);
for (ic = 0; ic < dllnum; ic++) { for (unsigned ic = 0; ic < dllnum; ic++) {
info(" DLL %3d %s %s", ic, idlls[ic]->name, idlls[ic]->shname); info(" DLL %3d %s %s", ic, idlls[ic]->name, idlls[ic]->shname);
} }
@ -936,7 +941,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
// create the new import table // create the new import table
addStubImports(); addStubImports();
for (ic = 0; ic < dllnum; ic++) { for (unsigned ic = 0; ic < dllnum; ic++) {
if (idlls[ic]->isk32) { if (idlls[ic]->isk32) {
// for kernel32.dll we need to put all the imported // for kernel32.dll we need to put all the imported
// ordinals into the output import table, as on // ordinals into the output import table, as on
@ -944,7 +949,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
if (strcasecmp(idlls[ic]->name, "kernel32.dll")) if (strcasecmp(idlls[ic]->name, "kernel32.dll"))
continue; continue;
if (idlls[ic]->ordinal) if (idlls[ic]->ordinal)
for (LEXX *tarr = idlls[ic]->lookupt; *tarr; tarr++) for (const LEXX *tarr = idlls[ic]->lookupt; *tarr; tarr++)
if (*tarr & ord_mask) { if (*tarr & ord_mask) {
ilinker->add(kernelDll(), *tarr & 0xffff); ilinker->add(kernelDll(), *tarr & 0xffff);
kernel32ordinal = true; kernel32ordinal = true;
@ -963,8 +968,8 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
// create the preprocessed data // create the preprocessed data
SPAN_S_VAR(byte, ppi, oimport); // preprocessed imports SPAN_S_VAR(byte, ppi, oimport); // preprocessed imports
for (ic = 0; ic < dllnum; ic++) { for (unsigned ic = 0; ic < dllnum; ic++) {
LEXX *tarr = idlls[ic]->lookupt; const LEXX *tarr = idlls[ic]->lookupt;
set_le32(ppi, ilinker->getAddress(idlls[ic]->name)); set_le32(ppi, ilinker->getAddress(idlls[ic]->name));
set_le32(ppi + 4, idlls[ic]->iat - rvamin); set_le32(ppi + 4, idlls[ic]->iat - rvamin);
ppi += 8; ppi += 8;
@ -982,8 +987,8 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
} }
} else { } else {
*ppi++ = 1; *ppi++ = 1;
unsigned const skip2 = 2 + *tarr; const unsigned skip2 = 2 + *tarr;
unsigned const take2 = 1 + strlen(ibuf.subref("bad import name %#x", skip2, 1)); const unsigned take2 = 1 + strlen(ibuf.subref("bad import name %#x", skip2, 1));
memcpy(ppi, ibuf.subref("bad import name %#x", skip2, take2), take2); memcpy(ppi, ibuf.subref("bad import name %#x", skip2, take2), take2);
ppi += take2; ppi += take2;
names.add(*tarr, 2 + take2); names.add(*tarr, 2 + take2);
@ -993,7 +998,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
unsigned esize = ptr_udiff_bytes(tarr, idlls[ic]->lookupt); unsigned esize = ptr_udiff_bytes(tarr, idlls[ic]->lookupt);
lookups.add(idlls[ic]->lookupt, esize); lookups.add(idlls[ic]->lookupt, esize);
if (ptr_diff_bytes(ibuf.subref("bad import name %#x", idlls[ic]->iat, 1), if (ptr_diff_bytes(ibuf.subref("bad import name %#x", idlls[ic]->iat, 1),
(char *) idlls[ic]->lookupt) != 0) { idlls[ic]->lookupt) != 0) {
memcpy(ibuf.subref("bad import name %#x", idlls[ic]->iat, esize), idlls[ic]->lookupt, memcpy(ibuf.subref("bad import name %#x", idlls[ic]->iat, esize), idlls[ic]->lookupt,
esize); esize);
iats.add(idlls[ic]->iat, esize); iats.add(idlls[ic]->iat, esize);
@ -1022,13 +1027,13 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
names.dump(); names.dump();
#endif #endif
// do some work for the unpacker // do some work for the unpacker
im = im_save; for (unsigned ic = 0; ic < dllnum; ic++) {
for (ic = 0; ic < dllnum; ic++, im++) { import_desc *const im = im_start + ic;
memset(im, FILLVAL, sizeof(*im)); memset(im, FILLVAL, sizeof(*im));
im->dllname = ptr_diff_bytes(dlls[idlls[ic]->original_position].name, ibuf); im->dllname = ptr_udiff_bytes(dlls[idlls[ic]->original_position].name, ibuf);
} }
} else { } else {
iats.add(im_save, sizeof(import_desc) * dllnum); iats.add(im_start, sizeof(import_desc) * dllnum);
// zero unneeded data // zero unneeded data
iats.clear(); iats.clear();
lookups.clear(); lookups.clear();
@ -1038,7 +1043,7 @@ unsigned PeFile::processImports0(ord_mask_t ord_mask) // pass 1
iats.add(&names); iats.add(&names);
iats.add(&lookups); iats.add(&lookups);
iats.flatten(); iats.flatten();
for (ic = 0; ic < iats.ivnum; ic++) for (unsigned ic = 0; ic < iats.ivnum; ic++)
ilen += iats.ivarr[ic].len; ilen += iats.ivarr[ic].len;
info("Imports: original size: %u bytes, preprocessed size: %u bytes", ilen, soimport); info("Imports: original size: %u bytes, preprocessed size: %u bytes", ilen, soimport);
@ -1063,7 +1068,7 @@ PeFile::Export::~Export() {
delete[] functionptrs; delete[] functionptrs;
delete[] ordinals; delete[] ordinals;
if (names) { if (names) {
unsigned const limit = edir.names + edir.functions; const unsigned limit = edir.names + edir.functions;
for (unsigned ic = 0; ic < limit; ic++) for (unsigned ic = 0; ic < limit; ic++)
if (names[ic]) if (names[ic])
free(names[ic]); // allocated by strdup() free(names[ic]); // allocated by strdup()
@ -1247,12 +1252,11 @@ void PeFile::processTls1(Interval *iv, typename tls_traits<LEXX>::cb_value_t ima
if (isefi && IDSIZE(PEDIR_TLS)) if (isefi && IDSIZE(PEDIR_TLS))
throwCantPack("TLS not supported on EFI"); throwCantPack("TLS not supported on EFI");
unsigned const take = ALIGN_UP(IDSIZE(PEDIR_TLS), 4u); const unsigned take = ALIGN_UP(IDSIZE(PEDIR_TLS), 4u);
sotls = take; sotls = take;
if (!sotls) if (!sotls)
return; return;
const unsigned skip = IDADDR(PEDIR_TLS);
unsigned const skip = IDADDR(PEDIR_TLS);
const tls *const tlsp = (const tls *) ibuf.subref("bad tls %#x", skip, sizeof(tls)); const tls *const tlsp = (const tls *) ibuf.subref("bad tls %#x", skip, sizeof(tls));
// note: TLS callbacks are not implemented in Windows 95/98/ME // note: TLS callbacks are not implemented in Windows 95/98/ME
@ -1286,8 +1290,8 @@ void PeFile::processTls1(Interval *iv, typename tls_traits<LEXX>::cb_value_t ima
const unsigned tlsdataend = tlsp->dataend - imagebase; const unsigned tlsdataend = tlsp->dataend - imagebase;
// now some ugly stuff: find the relocation entries in the tls data area // now some ugly stuff: find the relocation entries in the tls data area
unsigned const take2 = IDSIZE(PEDIR_RELOC); const unsigned skip2 = IDADDR(PEDIR_RELOC);
unsigned const skip2 = IDADDR(PEDIR_RELOC); const unsigned take2 = IDSIZE(PEDIR_RELOC);
Reloc rel(ibuf.subref("bad tls reloc %#x", skip2, take2), take2); Reloc rel(ibuf.subref("bad tls reloc %#x", skip2, take2), take2);
unsigned pos, type; unsigned pos, type;
while (rel.next(pos, type)) while (rel.next(pos, type))
@ -1305,11 +1309,11 @@ void PeFile::processTls1(Interval *iv, typename tls_traits<LEXX>::cb_value_t ima
mb_otls.alloc(aligned_sotls); mb_otls.alloc(aligned_sotls);
mb_otls.clear(); mb_otls.clear();
otls = mb_otls; // => otls now is a SPAN_S otls = mb_otls; // => otls now is a SPAN_S
unsigned const take1 = sizeof(tls); const unsigned skip1 = IDADDR(PEDIR_TLS);
unsigned const skip1 = IDADDR(PEDIR_TLS); const unsigned take1 = sizeof(tls);
memcpy(otls, ibuf.subref("bad tls %#x", skip1, take1), take1); memcpy(otls, ibuf.subref("bad tls %#x", skip1, take1), take1);
// WARNING: this can access data in BSS // WARNING: this can access data in BSS
unsigned const take3 = sotls - sizeof(tls); const unsigned take3 = sotls - sizeof(tls);
memcpy(otls + sizeof(tls), ibuf.subref("bad tls %#x", tlsdatastart, take3), take3); memcpy(otls + sizeof(tls), ibuf.subref("bad tls %#x", tlsdatastart, take3), take3);
tlsindex = tlsp->tlsindex - imagebase; tlsindex = tlsp->tlsindex - imagebase;
// NEW: subtract two dwords if TLS callbacks are used - Stefan Widmann // NEW: subtract two dwords if TLS callbacks are used - Stefan Widmann
@ -1392,14 +1396,14 @@ void PeFile::processLoadConf(Interval *iv) // pass 1
soloadconf = get_le32(loadconf); soloadconf = get_le32(loadconf);
if (soloadconf == 0) if (soloadconf == 0)
return; return;
static unsigned const MAX_SOLOADCONF = 256; // XXX FIXME: Why? static const unsigned MAX_SOLOADCONF = 256; // XXX FIXME: Why?
if (soloadconf > MAX_SOLOADCONF) if (soloadconf > MAX_SOLOADCONF)
info("Load Configuration directory %u > %u", soloadconf, MAX_SOLOADCONF); info("Load Configuration directory %u > %u", soloadconf, MAX_SOLOADCONF);
// if there were relocation entries referring to the load config table // if there were relocation entries referring to the load config table
// then we need them for the copy of the table too // then we need them for the copy of the table too
unsigned const take = IDSIZE(PEDIR_RELOC); const unsigned skip = IDADDR(PEDIR_RELOC);
unsigned const skip = IDADDR(PEDIR_RELOC); const unsigned take = IDSIZE(PEDIR_RELOC);
Reloc rel(ibuf.subref("bad reloc %#x", skip, take), take); Reloc rel(ibuf.subref("bad reloc %#x", skip, take), take);
unsigned pos, type; unsigned pos, type;
while (rel.next(pos, type)) while (rel.next(pos, type))
@ -1876,7 +1880,7 @@ void PeFile::processResources(Resource *res) {
set_le32(ores, res->offs()); // save original offset set_le32(ores, res->offs()); // save original offset
ores += 4; ores += 4;
unsigned const take = res->size(); const unsigned take = res->size();
ICHECK(ibuf + res->offs(), take); ICHECK(ibuf + res->offs(), take);
memcpy(ores, ibuf.subref("bad resoff %#x", res->offs(), take), take); memcpy(ores, ibuf.subref("bad resoff %#x", res->offs(), take), take);
ibuf.fill(res->offs(), take, FILLVAL); ibuf.fill(res->offs(), take, FILLVAL);
@ -1944,8 +1948,8 @@ unsigned PeFile::stripDebug(unsigned overlaystart) {
COMPILE_TIME_ASSERT(sizeof(((debug_dir_t *) nullptr)->_) == 16) COMPILE_TIME_ASSERT(sizeof(((debug_dir_t *) nullptr)->_) == 16)
COMPILE_TIME_ASSERT(sizeof(((debug_dir_t *) nullptr)->__) == 4) COMPILE_TIME_ASSERT(sizeof(((debug_dir_t *) nullptr)->__) == 4)
unsigned const take = IDSIZE(PEDIR_DEBUG); const unsigned skip = IDADDR(PEDIR_DEBUG);
unsigned const skip = IDADDR(PEDIR_DEBUG); const unsigned take = IDSIZE(PEDIR_DEBUG);
const debug_dir_t *dd = (const debug_dir_t *) ibuf.subref("bad debug %#x", skip, take); const debug_dir_t *dd = (const debug_dir_t *) ibuf.subref("bad debug %#x", skip, take);
for (unsigned ic = 0; ic < IDSIZE(PEDIR_DEBUG) / sizeof(debug_dir_t); ic++, dd++) for (unsigned ic = 0; ic < IDSIZE(PEDIR_DEBUG) / sizeof(debug_dir_t); ic++, dd++)
if (overlaystart == dd->fpos) if (overlaystart == dd->fpos)
@ -1971,7 +1975,7 @@ void PeFile::readSectionHeaders(unsigned objs, unsigned sizeof_ih) {
fi->seek(pe_offset + sizeof_ih, SEEK_SET); fi->seek(pe_offset + sizeof_ih, SEEK_SET);
fi->readx(isection, sizeof(pe_section_t) * objs); fi->readx(isection, sizeof(pe_section_t) * objs);
rvamin = isection[0].vaddr; rvamin = isection[0].vaddr;
unsigned const rvalast = isection[-1 + objs].vsize + isection[-1 + objs].vaddr; const unsigned rvalast = isection[-1 + objs].vsize + isection[-1 + objs].vaddr;
for (unsigned j = 0; j < objs; ++j) { // expect: first is min, last is max for (unsigned j = 0; j < objs; ++j) { // expect: first is min, last is max
unsigned lo = isection[j].vaddr, hi = isection[j].vsize + lo; unsigned lo = isection[j].vaddr, hi = isection[j].vsize + lo;
if (hi < lo) { // this checks first and last sections, too! if (hi < lo) { // this checks first and last sections, too!
@ -2649,11 +2653,12 @@ void PeFile::rebuildTls() {
namespace { namespace {
template <class T> template <class T>
struct VPtr { struct VPtr { // "virtual pointer" pointing before a buffer
static_assert(sizeof(T) == 1); static_assert(sizeof(T) == 1);
SPAN_S(T) ptr; SPAN_S(T) base;
size_t vaddr; size_t x;
auto operator+(size_t n) const { return ptr + mem_size(sizeof(T), n - vaddr); } // return base + (n - x)
auto operator+(size_t n) const { return base + mem_size_get_n(sizeof(T), n - x); }
}; };
} // namespace } // namespace
@ -2726,20 +2731,10 @@ void PeFile::rebuildImports(SPAN_S(byte) & extra_info, ord_mask_t ord_mask, bool
// INFO: use VPtr for "virtual pointer" pointing before a buffer // INFO: use VPtr for "virtual pointer" pointing before a buffer
//// byte *const Obuf = obuf.raw_bytes(0) - rvamin; //// byte *const Obuf = obuf.raw_bytes(0) - rvamin;
VPtr<byte> const Obuf{obuf, rvamin}; VPtr<byte> const Obuf{obuf, rvamin};
#if 0 SPAN_S_VAR(import_desc, im, (import_desc *) raw_bytes(Obuf + ODADDR(PEDIR_IMPORT), 0), obuf);
import_desc * const im0 = (import_desc*) (Obuf + ODADDR(PEDIR_IMPORT));
import_desc *im = im0;
byte *dllnames = Obuf + inamespos;
byte *importednames = dllnames + sdllnames;
byte * const importednames_start = importednames;
#else
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 ? raw_bytes(Obuf + inamespos, 0) : 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, inamespos ? dllnames + sdllnames : nullptr);
SPAN_0_VAR(byte, const importednames_start, importednames); SPAN_0_VAR(byte, importednames, importednames_start);
#endif
for (p = imdata; get_le32(p) != 0; ++p) { for (p = imdata; get_le32(p) != 0; ++p) {
// restore the name of the dll // restore the name of the dll

View File

@ -184,7 +184,7 @@ protected:
struct alignas(1) import_desc { struct alignas(1) import_desc {
LE32 oft; // orig first thunk LE32 oft; // orig first thunk
char _[8]; byte _[8];
LE32 dllname; LE32 dllname;
LE32 iat; // import address table LE32 iat; // import address table
}; };
@ -195,7 +195,7 @@ protected:
LE32 vaddr; LE32 vaddr;
LE32 size; LE32 size;
LE32 rawdataptr; LE32 rawdataptr;
char _[12]; byte _[12];
LE32 flags; LE32 flags;
}; };
@ -433,9 +433,9 @@ protected:
class Export : private noncopyable { class Export : private noncopyable {
struct alignas(1) export_dir_t { struct alignas(1) export_dir_t {
char _[12]; // flags, timedate, version byte _[12]; // flags, timedate, version
LE32 name; LE32 name;
char __[4]; // ordinal base byte __[4]; // ordinal base
LE32 functions; LE32 functions;
LE32 names; LE32 names;
LE32 addrtable; LE32 addrtable;
@ -483,16 +483,16 @@ protected:
struct alignas(1) pe_header_t { struct alignas(1) pe_header_t {
// 0x00 // 0x00
char _[4]; // pemagic byte _[4]; // pemagic
// 0x04 IMAGE_FILE_HEADER // 0x04 IMAGE_FILE_HEADER
LE16 cpu; // IMAGE_FILE_MACHINE_xxx LE16 cpu; // IMAGE_FILE_MACHINE_xxx
LE16 objects; // NumberOfSections LE16 objects; // NumberOfSections
char __[12]; // timestamp + reserved byte __[12]; // timestamp + reserved
LE16 opthdrsize; // SizeOfOptionalHeader LE16 opthdrsize; // SizeOfOptionalHeader
LE16 flags; // Characteristics LE16 flags; // Characteristics
// 0x18 IMAGE_OPTIONAL_HEADER32 // 0x18 IMAGE_OPTIONAL_HEADER32
LE16 coffmagic; // NEW: Stefan Widmann LE16 coffmagic; // NEW: Stefan Widmann
char ___[2]; // linkerversion byte ___[2]; // linkerversion
LE32 codesize; LE32 codesize;
// 0x20 // 0x20
LE32 datasize; LE32 datasize;
@ -506,7 +506,7 @@ protected:
LE32 objectalign; LE32 objectalign;
LE32 filealign; // should set to 0x200 ? LE32 filealign; // should set to 0x200 ?
// 0x40 // 0x40
char ____[16]; // versions byte ____[16]; // versions
// 0x50 // 0x50
LE32 imagesize; LE32 imagesize;
LE32 headersize; LE32 headersize;
@ -514,7 +514,7 @@ protected:
LE16 subsystem; // IMAGE_SUBSYSTEM_xxx LE16 subsystem; // IMAGE_SUBSYSTEM_xxx
LE16 dllflags; // IMAGE_DLLCHARACTERISTICS_xxx LE16 dllflags; // IMAGE_DLLCHARACTERISTICS_xxx
// 0x60 // 0x60
char _____[20]; // stack + heap sizes byte _____[20]; // stack + heap sizes
// 0x74 // 0x74
LE32 ddirsentries; // usually 16 LE32 ddirsentries; // usually 16
// 0x78 // 0x78
@ -544,16 +544,16 @@ protected:
struct alignas(1) pe_header_t { struct alignas(1) pe_header_t {
// 0x00 // 0x00
char _[4]; // pemagic byte _[4]; // pemagic
// 0x04 IMAGE_FILE_HEADER // 0x04 IMAGE_FILE_HEADER
LE16 cpu; // IMAGE_FILE_MACHINE_xxx LE16 cpu; // IMAGE_FILE_MACHINE_xxx
LE16 objects; // NumberOfSections LE16 objects; // NumberOfSections
char __[12]; // timestamp + reserved byte __[12]; // timestamp + reserved
LE16 opthdrsize; // SizeOfOptionalHeader LE16 opthdrsize; // SizeOfOptionalHeader
LE16 flags; // Characteristics LE16 flags; // Characteristics
// 0x18 IMAGE_OPTIONAL_HEADER64 // 0x18 IMAGE_OPTIONAL_HEADER64
LE16 coffmagic; // NEW: Stefan Widmann LE16 coffmagic; // NEW: Stefan Widmann
char ___[2]; // linkerversion byte ___[2]; // linkerversion
LE32 codesize; LE32 codesize;
// 0x20 // 0x20
LE32 datasize; LE32 datasize;
@ -567,7 +567,7 @@ protected:
LE32 objectalign; LE32 objectalign;
LE32 filealign; // should set to 0x200 ? LE32 filealign; // should set to 0x200 ?
// 0x40 // 0x40
char ____[16]; // versions byte ____[16]; // versions
// 0x50 // 0x50
LE32 imagesize; LE32 imagesize;
LE32 headersize; LE32 headersize;
@ -575,7 +575,7 @@ protected:
LE16 subsystem; // IMAGE_SUBSYSTEM_xxx LE16 subsystem; // IMAGE_SUBSYSTEM_xxx
LE16 dllflags; // IMAGE_DLLCHARACTERISTICS_xxx LE16 dllflags; // IMAGE_DLLCHARACTERISTICS_xxx
// 0x60 // 0x60
char _____[36]; // stack + heap sizes + loader flag byte _____[36]; // stack + heap sizes + loader flag
// 0x84 // 0x84
LE32 ddirsentries; // usually 16 LE32 ddirsentries; // usually 16
// 0x88 // 0x88

View File

@ -46,7 +46,7 @@
; Revision history: ; Revision history:
; ;
; 93/12/05 DJ Delorie Initial version v2.00, requires DPMI 0.9 ; 93/12/05 DJ Delorie Initial version v2.00, requires DPMI 0.9
; 94/10/13 CW Sandmann v2.01, accumlated changes: 60K load bug, limits, cwsdpmi, optimization ; 94/10/13 CW Sandmann v2.01, accumulated changes: 60K load bug, limits, cwsdpmi, optimization
; 94/10/29 CW Sandmann v2.03, M Welinder changes; cwsdpmi load anywhere, size decrease ; 94/10/29 CW Sandmann v2.03, M Welinder changes; cwsdpmi load anywhere, size decrease
; ;
.copyright "The STUB.EXE stub loader is Copyright (C) 1993-1995 DJ Delorie. " .copyright "The STUB.EXE stub loader is Copyright (C) 1993-1995 DJ Delorie. "

View File

@ -25,8 +25,9 @@
<markus@oberhumer.com> <ezerotven+github@gmail.com> <markus@oberhumer.com> <ezerotven+github@gmail.com>
*/ */
#include "../headers.h"
#include <algorithm>
#include "../conf.h" #include "../conf.h"
#include "util.h"
#define ACC_WANT_ACC_INCI_H 1 #define ACC_WANT_ACC_INCI_H 1
#include "../miniacc.h" #include "../miniacc.h"
@ -173,6 +174,7 @@ void uintptr_check_no_overlap(upx_uintptr_t a, size_t a_size, upx_uintptr_t b, s
throwCantPack("ptr_check_no_overlap-bc"); throwCantPack("ptr_check_no_overlap-bc");
} }
#if DEBUG
TEST_CASE("ptr_check_no_overlap 2") { TEST_CASE("ptr_check_no_overlap 2") {
byte p[4] = {}; byte p[4] = {};
@ -243,6 +245,7 @@ TEST_CASE("ptr_check_no_overlap 3") {
check_throws_(0, 4, 3, 0, 1, 0); check_throws_(0, 4, 3, 0, 1, 0);
check_throws_(0, 4, 4, 0, 1, 0); check_throws_(0, 4, 4, 0, 1, 0);
} }
#endif // DEBUG
/************************************************************************* /*************************************************************************
// bele.h // bele.h
@ -270,31 +273,34 @@ void *upx_calloc(size_t n, size_t element_size) {
return p; return p;
} }
// extremely simple stable sort: Gnomesort // simple unoptimized memswap()
// WARNING: O(n**2) !!!!! void upx_memswap(void *a, void *b, size_t n) {
void upx_stable_sort(void *base, size_t n, size_t element_size, if (a != b && n != 0) {
int(__acc_cdecl_qsort *compare)(const void *, const void *)) { char *x = (char *) a;
(void) mem_size(element_size, n); // assert size char *y = (char *) b;
for (size_t i = 1; i < n;) { do {
char *a = (char *) base + element_size * i; // a = &array[i] char tmp = *x;
if (i == 0 || (compare(a - element_size, a) <= 0)) { *x++ = *y;
i += 1; *y++ = tmp;
} else { } while (--n != 0);
i -= 1; }
// swap elements a[-1] <=> a[0] }
// upx_memswap(a - element_size, a, element_size);
size_t j = element_size; // extremely simple (and beautiful) stable sort: Gnomesort
do { // WARNING: O(n^2) and thus very inefficient for large n
char tmp = *(a - element_size); void upx_stable_sort(void *array, size_t n, size_t element_size,
*(a - element_size) = *a; int (*compare)(const void *, const void *)) {
*a++ = tmp; for (size_t i = 1; i < n; i++) {
} while (--j != 0); char *a = (char *) array + element_size * i; // a = &array[i]
if (i != 0 && compare(a - element_size, a) > 0) {
upx_memswap(a - element_size, a, element_size); // swap elements a[-1] <=> a[0]
i -= 2;
} }
} }
} }
#if DEBUG
TEST_CASE("upx_stable_sort") { TEST_CASE("upx_stable_sort") {
// TODO C++20: use std::next_permutation() to test all permutations
{ {
unsigned a[] = {0, 1}; unsigned a[] = {0, 1};
upx_stable_sort(a, 2, sizeof(*a), ne32_compare); upx_stable_sort(a, 2, sizeof(*a), ne32_compare);
@ -310,7 +316,19 @@ TEST_CASE("upx_stable_sort") {
upx_stable_sort(a, 3, sizeof(*a), ne32_compare); upx_stable_sort(a, 3, sizeof(*a), ne32_compare);
CHECK((a[0] == 0 && a[1] == 1 && a[2] == 2)); CHECK((a[0] == 0 && a[1] == 1 && a[2] == 2));
} }
#if __cplusplus >= 202002L // use C++20 std::next_permutation() to test all permutations
{
upx_uint16_t perm[5] = {0, 1, 2, 3, 4}; // 120 permutations
do {
upx_uint16_t a[5] = {};
memcpy(a, perm, sizeof(perm));
upx_stable_sort(a, 5, sizeof(*a), ne16_compare);
CHECK((a[0] == 0 && a[1] == 1 && a[2] == 2 && a[3] == 3 && a[4] == 4));
} while (std::next_permutation(perm, perm + 5));
}
#endif
} }
#endif // DEBUG
/************************************************************************* /*************************************************************************
// qsort() util // qsort() util

View File

@ -133,8 +133,10 @@ forceinline void ptr_check_no_overlap(const void *a, size_t a_size, const void *
void *upx_calloc(size_t n, size_t element_size); void *upx_calloc(size_t n, size_t element_size);
void upx_stable_sort(void *base, size_t n, size_t element_size, void upx_memswap(void *a, void *b, size_t n);
int(__acc_cdecl_qsort *compare)(const void *, const void *));
void upx_stable_sort(void *array, size_t n, size_t element_size,
int (*compare)(const void *, const void *));
/************************************************************************* /*************************************************************************
// misc. support functions // misc. support functions