Adding exe2exe.

This commit is contained in:
Nicolas "Pixel" Noble
2026-07-20 18:42:13 -07:00
parent 55eafd76a0
commit dda16d57fe
11 changed files with 330 additions and 5 deletions
+1 -1
View File
@@ -85,7 +85,7 @@ SRCS += $(wildcard third_party/cueparser/*.c)
SRCS += $(wildcard third_party/iec-60908b/*.c)
SRCS += third_party/ucl/src/n2e_99.c third_party/ucl/src/alloc.c
TOOLS = authoring exe2elf exe2iso modconv ps1-packer psyq-obj-parser
TOOLS = authoring exe2elf exe2exe exe2iso midi2psm midi2spd modconv ps1-packer psyq-obj-parser
##############################################################################
+1
View File
@@ -41,6 +41,7 @@ bins/
/pcsx-redux
/authoring
/exe2elf
/exe2exe
/exe2iso
/modconv
/ps1-packer
+1 -1
View File
@@ -175,7 +175,7 @@ SUPPORT_SRCS += third_party/ucl/src/n2e_99.c third_party/ucl/src/alloc.c third_p
SUPPORT_SRCS += $(wildcard third_party/iec-60908b/*.c)
LIBS := third_party/luajit/src/libluajit.a
TOOLS = authoring exe2elf exe2iso midi2psm midi2spd modconv ps1-packer psyq-obj-parser
TOOLS = authoring exe2elf exe2exe exe2iso midi2psm midi2spd modconv ps1-packer psyq-obj-parser
##############################################################################
+2
View File
@@ -64,6 +64,7 @@ steps:
vsprojects/x64/ReleaseCLI/crashpad_handler.exe
vsprojects/x64/ReleaseCLI/authoring.exe
vsprojects/x64/ReleaseCLI/exe2elf.exe
vsprojects/x64/ReleaseCLI/exe2exe.exe
vsprojects/x64/ReleaseCLI/exe2iso.exe
vsprojects/x64/ReleaseCLI/modconv.exe
vsprojects/x64/ReleaseCLI/ps1-packer.exe
@@ -85,6 +86,7 @@ steps:
!**\crashpad_handler.exe
!**\authoring.exe
!**\exe2elf.exe
!**\exe2exe.exe
!**\exe2iso.exe
!**\modconv.exe
!**\midi2psm.exe
+1
View File
@@ -93,6 +93,7 @@ steps:
!**\crashpad_handler.exe
!**\authoring.exe
!**\exe2elf.exe
!**\exe2exe.exe
!**\exe2iso.exe
!**\modconv.exe
!**\midi2psm.exe
+14 -3
View File
@@ -223,6 +223,7 @@ bool loadELF(IO<File> file, IO<File> dest, BinaryLoader::Info& info, std::map<ui
info.pc = reader.get_entry();
Elf_Half sec_num = reader.sections.size();
Elf_Half seg_num = reader.segments.size();
for (unsigned i = 0; i < sec_num; i++) {
section* psec = reader.sections[i];
@@ -234,9 +235,19 @@ bool loadELF(IO<File> file, IO<File> dest, BinaryLoader::Info& info, std::map<ui
auto size = psec->get_size();
auto data = psec->get_data();
auto addr = psec->get_address();
dest->writeAt(data, size, addr);
eraseSymbolsInSpan(addr, addr + size, symbols);
auto vaddr = psec->get_address();
auto loadAddr = vaddr;
for (unsigned j = 0; j < seg_num; j++) {
segment* pseg = reader.segments[j];
if (pseg->get_type() != PT_LOAD) continue;
auto segVaddr = pseg->get_virtual_address();
if (vaddr >= segVaddr && vaddr + size <= segVaddr + pseg->get_memory_size()) {
loadAddr = pseg->get_physical_address() + (vaddr - segVaddr);
break;
}
}
dest->writeAt(data, size, loadAddr);
eraseSymbolsInSpan(vaddr, vaddr + size, symbols);
}
for (unsigned i = 0; i < sec_num; i++) {
+1
View File
@@ -3,6 +3,7 @@
This directory contains tools designed to help with the PCSX-Redux project somehow. The top level, directly usable tools are:
* [exe2elf](exe2elf) - Converts a PS-EXE executable to an ELF file, which can be useful for loading and debugging through gdb.
* [exe2exe](exe2exe) - Converts a PlayStation executable to a PS-EXE executable, normalizing the binary in the process.
* [exe2iso](exe2iso) - Converts a PS-EXE executable to a bootable ISO file containing a single PSX.EXE, conformant to the ISO9660 standard and bootable on a retail PlayStation 1.
* [ghidra_scripts](ghidra_scripts) - A collection of Ghidra scripts that can be used to integrate some parts of PCSX-Redux into Ghidra and vice versa.
* [ps1-packer](ps1-packer) - A tool for compressing PlayStation 1 executables into a single self-decompressing binary in various formats.
+139
View File
@@ -0,0 +1,139 @@
/***************************************************************************
* Copyright (C) 2026 PCSX-Redux authors *
* *
* This program is free software; you can redistribute it and/or modify *
* it 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; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
***************************************************************************/
#include <stdint.h>
#include <vector>
#include "flags.h"
#include "fmt/format.h"
#include "support/file.h"
#include "support/mem4g.h"
#include "supportpsx/binloader.h"
int main(int argc, char** argv) {
CommandLine::args args(argc, argv);
auto output = args.get<std::string>("o");
fmt::print(R"(
exe2exe by Nicolas "Pixel" Noble
https://github.com/grumpycoders/pcsx-redux/tree/main/tools/exe2exe/
)");
const auto inputs = args.positional();
const bool asksForHelp = args.get<bool>("h").value_or(false);
const bool hasOutput = output.has_value();
const bool oneInput = inputs.size() == 1;
if (asksForHelp || !oneInput || !hasOutput) {
fmt::print(R"(
Usage: {} input.ps-exe [-h] -o output.ps-exe
input.ps-exe mandatory: specify the input binary file.
-o output.ps-exe mandatory: name of the output file.
-h displays this help information and exit.
Valid input binary files can be in the following formats:
- PS-EXE (needs the "PS-X EXE" signature)
- ELF
- CPE
- PSF
- MiniPSF
)",
argv[0]);
return -1;
}
auto& input = inputs[0];
PCSX::IO<PCSX::File> file(new PCSX::PosixFile(input));
if (file->failed()) {
fmt::print("Unable to open file: {}\n", input);
return -1;
}
PCSX::BinaryLoader::Info info;
PCSX::IO<PCSX::Mem4G> memory(new PCSX::Mem4G());
std::map<uint32_t, std::string> symbols;
bool success = PCSX::BinaryLoader::load(file, memory, info, symbols);
if (!success) {
fmt::print("Unable to load file: {}\n", input);
return -1;
}
if (!info.pc.has_value()) {
fmt::print("File {} is invalid.\n", input);
return -1;
}
uint32_t tload = memory->lowestAddress();
uint32_t pc = info.pc.value_or(0);
uint32_t gp = info.gp.value_or(0);
uint32_t sp = info.sp.value_or(0);
if (tload & 3) {
fmt::print("File {} is invalid: tload is not aligned to 4 bytes.\n", input);
return -1;
}
if (pc & 3) {
fmt::print("File {} is invalid: pc is not aligned to 4 bytes.\n", input);
return -1;
}
if (gp & 3) {
fmt::print("File {} is invalid: gp is not aligned to 4 bytes.\n", input);
return -1;
}
if (sp & 3) {
fmt::print("File {} is invalid: sp is not aligned to 4 bytes.\n", input);
return -1;
}
uint32_t size = memory->actualSize();
size = (size + 2047) & ~2047;
PCSX::IO<PCSX::File> out = new PCSX::PosixFile(output.value().c_str(), PCSX::FileOps::TRUNCATE);
out->write<uint64_t>(0x45584520582d5350);
out->write<uint32_t>(0);
out->write<uint32_t>(0);
out->write<uint32_t>(pc);
out->write<uint32_t>(gp);
out->write<uint32_t>(tload);
out->write<uint32_t>(size);
out->write<uint32_t>(0);
out->write<uint32_t>(0);
out->write<uint32_t>(0);
out->write<uint32_t>(0);
out->write<uint32_t>(sp);
for (unsigned i = 0; i < 499; i++) {
out->write<uint32_t>(0);
}
auto data = memory.asA<PCSX::File>()->readAt(size, tload);
out->write(std::move(data));
fmt::print(R"(
Input file: {}
pc: 0x{:08x} gp: 0x{:08x} sp: 0x{:08x}
File {} created. All done.
)",
input, pc, gp, sp, output.value());
return 0;
}
+135
View File
@@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseWithClangCL|x64">
<Configuration>ReleaseWithClangCL</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>18.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{6a476694-c1f8-4ba6-aa33-07d70fb197f4}</ProjectGuid>
<RootNamespace>exe2exe</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v145</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithClangCL|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>ClangCL</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\common.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithClangCL|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\common.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Manifest>
<EnableSegmentHeap>true</EnableSegmentHeap>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Manifest>
<EnableSegmentHeap>true</EnableSegmentHeap>
</Manifest>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseWithClangCL|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp20</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<Manifest>
<EnableSegmentHeap>true</EnableSegmentHeap>
</Manifest>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\tools\exe2exe\exe2exe.cc" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\fmt\fmt.vcxproj">
<Project>{71772007-5110-418d-be9c-fb102b6eaabf}</Project>
</ProjectReference>
<ProjectReference Include="..\supportpsx\supportpsx.vcxproj">
<Project>{b2e2ad84-9d7f-4976-9572-e415819ffd7f}</Project>
</ProjectReference>
<ProjectReference Include="..\support\support.vcxproj">
<Project>{0e621321-093c-4d60-bd8b-027fdc2b0f63}</Project>
</ProjectReference>
<ProjectReference Include="..\zlib\zlib.vcxproj">
<Project>{3125e078-7261-48c4-803e-4b29ceeaa56b}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\tools\exe2exe\exe2exe.cc">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
+13
View File
@@ -331,6 +331,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "midi2spd", "midi2spd\midi2s
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "midi2psm", "midi2psm\midi2psm.vcxproj", "{E1D23582-C66F-40D3-A163-B1B4470B3F15}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "exe2exe", "exe2exe\exe2exe.vcxproj", "{6A476694-C1F8-4BA6-AA33-07D70FB197F4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -770,6 +772,16 @@ Global
{E1D23582-C66F-40D3-A163-B1B4470B3F15}.ReleaseWithClangCL|x64.Build.0 = ReleaseWithClangCL|x64
{E1D23582-C66F-40D3-A163-B1B4470B3F15}.ReleaseWithTracy|x64.ActiveCfg = Release|x64
{E1D23582-C66F-40D3-A163-B1B4470B3F15}.ReleaseWithTracy|x64.Build.0 = Release|x64
{6A476694-C1F8-4BA6-AA33-07D70FB197F4}.Debug|x64.ActiveCfg = Debug|x64
{6A476694-C1F8-4BA6-AA33-07D70FB197F4}.Debug|x64.Build.0 = Debug|x64
{6A476694-C1F8-4BA6-AA33-07D70FB197F4}.Release|x64.ActiveCfg = Release|x64
{6A476694-C1F8-4BA6-AA33-07D70FB197F4}.Release|x64.Build.0 = Release|x64
{6A476694-C1F8-4BA6-AA33-07D70FB197F4}.ReleaseCLI|x64.ActiveCfg = ReleaseWithClangCL|x64
{6A476694-C1F8-4BA6-AA33-07D70FB197F4}.ReleaseCLI|x64.Build.0 = ReleaseWithClangCL|x64
{6A476694-C1F8-4BA6-AA33-07D70FB197F4}.ReleaseWithClangCL|x64.ActiveCfg = ReleaseWithClangCL|x64
{6A476694-C1F8-4BA6-AA33-07D70FB197F4}.ReleaseWithClangCL|x64.Build.0 = ReleaseWithClangCL|x64
{6A476694-C1F8-4BA6-AA33-07D70FB197F4}.ReleaseWithTracy|x64.ActiveCfg = Release|x64
{6A476694-C1F8-4BA6-AA33-07D70FB197F4}.ReleaseWithTracy|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -826,6 +838,7 @@ Global
{ACCFF71D-6BB0-4B55-9ADA-476E2A7F071F} = {F3837DDD-BF8B-497F-B876-9934BF472AB3}
{FC0BCB98-8E1A-4304-BFF0-B22970853019} = {C6DD47BC-0C38-4AE6-B517-9675F3AC8A50}
{E1D23582-C66F-40D3-A163-B1B4470B3F15} = {C6DD47BC-0C38-4AE6-B517-9675F3AC8A50}
{6A476694-C1F8-4BA6-AA33-07D70FB197F4} = {C6DD47BC-0C38-4AE6-B517-9675F3AC8A50}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {284E91C1-764E-441A-854D-CFD3623A6501}