diff options
author | RĂ©mi Verschelde <remi@verschelde.fr> | 2022-04-27 14:29:21 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-27 14:29:21 +0200 |
commit | 504708ae21b9722ddbf33a2d557a6a9ed0d70855 (patch) | |
tree | daecd7e3170d2bc4f912f990485ca2359f86ea78 /platform | |
parent | 3e9ead05f2e87e46b5982cc9a140e172ee98c227 (diff) | |
parent | c0cc41d6c1bb7b9fb4897debb15f1f083d3c1d02 (diff) |
Merge pull request #56093 from bruvzg/pck_section_load
Improve embedded PCK loading and exporting.
Diffstat (limited to 'platform')
-rw-r--r-- | platform/linuxbsd/os_linuxbsd.cpp | 85 | ||||
-rw-r--r-- | platform/linuxbsd/os_linuxbsd.h | 2 | ||||
-rw-r--r-- | platform/windows/export/export_plugin.cpp | 56 | ||||
-rw-r--r-- | platform/windows/export/export_plugin.h | 2 | ||||
-rw-r--r-- | platform/windows/godot_windows.cpp | 18 | ||||
-rw-r--r-- | platform/windows/os_windows.cpp | 52 | ||||
-rw-r--r-- | platform/windows/os_windows.h | 2 |
7 files changed, 194 insertions, 23 deletions
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index bf142f8804..b73d4dc626 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -242,6 +242,91 @@ bool OS_LinuxBSD::_check_internal_feature_support(const String &p_feature) { return p_feature == "pc"; } +uint64_t OS_LinuxBSD::get_embedded_pck_offset() const { + Ref<FileAccess> f = FileAccess::open(get_executable_path(), FileAccess::READ); + if (f.is_null()) { + return 0; + } + + // Read and check ELF magic number. + { + uint32_t magic = f->get_32(); + if (magic != 0x464c457f) { // 0x7F + "ELF" + return 0; + } + } + + // Read program architecture bits from class field. + int bits = f->get_8() * 32; + + // Get info about the section header table. + int64_t section_table_pos; + int64_t section_header_size; + if (bits == 32) { + section_header_size = 40; + f->seek(0x20); + section_table_pos = f->get_32(); + f->seek(0x30); + } else { // 64 + section_header_size = 64; + f->seek(0x28); + section_table_pos = f->get_64(); + f->seek(0x3c); + } + int num_sections = f->get_16(); + int string_section_idx = f->get_16(); + + // Load the strings table. + uint8_t *strings; + { + // Jump to the strings section header. + f->seek(section_table_pos + string_section_idx * section_header_size); + + // Read strings data size and offset. + int64_t string_data_pos; + int64_t string_data_size; + if (bits == 32) { + f->seek(f->get_position() + 0x10); + string_data_pos = f->get_32(); + string_data_size = f->get_32(); + } else { // 64 + f->seek(f->get_position() + 0x18); + string_data_pos = f->get_64(); + string_data_size = f->get_64(); + } + + // Read strings data. + f->seek(string_data_pos); + strings = (uint8_t *)memalloc(string_data_size); + if (!strings) { + return 0; + } + f->get_buffer(strings, string_data_size); + } + + // Search for the "pck" section. + int64_t off = 0; + for (int i = 0; i < num_sections; ++i) { + int64_t section_header_pos = section_table_pos + i * section_header_size; + f->seek(section_header_pos); + + uint32_t name_offset = f->get_32(); + if (strcmp((char *)strings + name_offset, "pck") == 0) { + if (bits == 32) { + f->seek(section_header_pos + 0x10); + off = f->get_32(); + } else { // 64 + f->seek(section_header_pos + 0x18); + off = f->get_64(); + } + break; + } + } + memfree(strings); + + return off; +} + String OS_LinuxBSD::get_config_path() const { if (has_environment("XDG_CONFIG_HOME")) { if (get_environment("XDG_CONFIG_HOME").is_absolute_path()) { diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h index 7b912ddee3..3f97b86eae 100644 --- a/platform/linuxbsd/os_linuxbsd.h +++ b/platform/linuxbsd/os_linuxbsd.h @@ -78,6 +78,8 @@ public: virtual MainLoop *get_main_loop() const override; + virtual uint64_t get_embedded_pck_offset() const override; + virtual String get_config_path() const override; virtual String get_data_path() const override; virtual String get_cache_path() const override; diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp index 917a0af90b..4c91163d2b 100644 --- a/platform/windows/export/export_plugin.cpp +++ b/platform/windows/export/export_plugin.cpp @@ -54,16 +54,23 @@ Error EditorExportPlatformWindows::_export_debug_script(const Ref<EditorExportPr } Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { - Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, p_path, p_flags); - - if (err != OK) { - return err; + String pck_path = p_path; + if (p_preset->get("binary_format/embed_pck")) { + pck_path = p_path.get_basename() + ".tmp"; + } + Error err = EditorExportPlatformPC::prepare_template(p_preset, p_debug, pck_path, p_flags); + if (p_preset->get("application/modify_resources") && err == OK) { + err = _rcedit_add_data(p_preset, pck_path); + } + if (err == OK) { + err = EditorExportPlatformPC::export_project_data(p_preset, p_debug, pck_path, p_flags); } - - _rcedit_add_data(p_preset, p_path); - if (p_preset->get("codesign/enable") && err == OK) { - err = _code_sign(p_preset, p_path); + err = _code_sign(p_preset, pck_path); + } + if (p_preset->get("binary_format/embed_pck") && err == OK) { + Ref<DirAccess> tmp_dir = DirAccess::create_for_path(p_path.get_base_dir()); + err = tmp_dir->rename(pck_path, p_path); } String app_name; @@ -117,6 +124,7 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/description"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray())); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/modify_resources"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0.0"), "")); @@ -127,17 +135,20 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), "")); } -void EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path) { +Error EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path) { String rcedit_path = EditorSettings::get_singleton()->get("export/windows/rcedit"); if (rcedit_path.is_empty()) { WARN_PRINT("The rcedit tool is not configured in the Editor Settings (Export > Windows > Rcedit). No custom icon or app information data will be embedded in the exported executable."); - return; + return ERR_FILE_NOT_FOUND; } if (!FileAccess::exists(rcedit_path)) { ERR_PRINT("Could not find rcedit executable at " + rcedit_path + ", no icon or app information data will be included."); - return; + return ERR_FILE_NOT_FOUND; + } + if (rcedit_path.is_empty()) { + rcedit_path = "rcedit"; // try to run signtool from PATH } #ifndef WINDOWS_ENABLED @@ -146,7 +157,7 @@ void EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> if (!wine_path.is_empty() && !FileAccess::exists(wine_path)) { ERR_PRINT("Could not find wine executable at " + wine_path + ", no icon or app information data will be included."); - return; + return ERR_FILE_NOT_FOUND; } if (wine_path.is_empty()) { @@ -204,13 +215,22 @@ void EditorExportPlatformWindows::_rcedit_add_data(const Ref<EditorExportPreset> args.push_back(trademarks); } -#ifdef WINDOWS_ENABLED - OS::get_singleton()->execute(rcedit_path, args); -#else +#ifndef WINDOWS_ENABLED // On non-Windows we need WINE to run rcedit args.push_front(rcedit_path); - OS::get_singleton()->execute(wine_path, args); + rcedit_path = wine_path; #endif + + String str; + Error err = OS::get_singleton()->execute(rcedit_path, args, &str, nullptr, true); + ERR_FAIL_COND_V(err != OK, err); + print_line("rcedit (" + p_path + "): " + str); + + if (str.find("Fatal error") != -1) { + return FAILED; + } + + return OK; } Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path) { @@ -417,6 +437,10 @@ bool EditorExportPlatformWindows::can_export(const Ref<EditorExportPreset> &p_pr Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const { // Patch the header of the "pck" section in the PE file so that it corresponds to the embedded data + if (p_embedded_size + p_embedded_start >= 0x100000000) { // Check for total executable size + ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Windows executables cannot be >= 4 GiB."); + } + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ_WRITE); if (f.is_null()) { return ERR_CANT_OPEN; diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h index 39d1cf4c77..c33c7f1f63 100644 --- a/platform/windows/export/export_plugin.h +++ b/platform/windows/export/export_plugin.h @@ -38,7 +38,7 @@ #include "platform/windows/logo.gen.h" class EditorExportPlatformWindows : public EditorExportPlatformPC { - void _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path); + Error _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path); Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path); Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path); diff --git a/platform/windows/godot_windows.cpp b/platform/windows/godot_windows.cpp index ad4e3ae77c..8de3ef294a 100644 --- a/platform/windows/godot_windows.cpp +++ b/platform/windows/godot_windows.cpp @@ -39,7 +39,18 @@ #ifndef TOOLS_ENABLED #if defined _MSC_VER #pragma section("pck", read) -__declspec(allocate("pck")) static const char dummy[8] = { 0 }; +__declspec(allocate("pck")) static char dummy[8] = { 0 }; + +// Dummy function to prevent LTO from discarding "pck" section. +extern "C" char *__cdecl pck_section_dummy_call() { + return &dummy[0]; +}; +#if defined _AMD64_ +#pragma comment(linker, "/include:pck_section_dummy_call") +#elif defined _X86_ +#pragma comment(linker, "/include:_pck_section_dummy_call") +#endif + #elif defined __GNUC__ static const char dummy[8] __attribute__((section("pck"), used)) = { 0 }; #endif @@ -140,11 +151,6 @@ int widechar_main(int argc, wchar_t **argv) { setlocale(LC_CTYPE, ""); -#ifndef TOOLS_ENABLED - // Workaround to prevent LTCG (MSVC LTO) from removing "pck" section - const char *dummy_guard = dummy; -#endif - char **argv_utf8 = new char *[argc]; for (int i = 0; i < argc; ++i) { diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index b4669e452a..8755bc65dc 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -686,6 +686,58 @@ MainLoop *OS_Windows::get_main_loop() const { return main_loop; } +uint64_t OS_Windows::get_embedded_pck_offset() const { + Ref<FileAccess> f = FileAccess::open(get_executable_path(), FileAccess::READ); + if (f.is_null()) { + return 0; + } + + // Process header. + { + f->seek(0x3c); + uint32_t pe_pos = f->get_32(); + + f->seek(pe_pos); + uint32_t magic = f->get_32(); + if (magic != 0x00004550) { + return 0; + } + } + + int num_sections; + { + int64_t header_pos = f->get_position(); + + f->seek(header_pos + 2); + num_sections = f->get_16(); + f->seek(header_pos + 16); + uint16_t opt_header_size = f->get_16(); + + // Skip rest of header + optional header to go to the section headers. + f->seek(f->get_position() + 2 + opt_header_size); + } + int64_t section_table_pos = f->get_position(); + + // Search for the "pck" section. + int64_t off = 0; + for (int i = 0; i < num_sections; ++i) { + int64_t section_header_pos = section_table_pos + i * 40; + f->seek(section_header_pos); + + uint8_t section_name[9]; + f->get_buffer(section_name, 8); + section_name[8] = '\0'; + + if (strcmp((char *)section_name, "pck") == 0) { + f->seek(section_header_pos + 20); + off = f->get_32(); + break; + } + } + + return off; +} + String OS_Windows::get_config_path() const { // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well. if (has_environment("XDG_CONFIG_HOME")) { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index adeecf37c5..370cb77fde 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -144,6 +144,8 @@ public: virtual int get_processor_count() const override; virtual String get_processor_name() const override; + virtual uint64_t get_embedded_pck_offset() const override; + virtual String get_config_path() const override; virtual String get_data_path() const override; virtual String get_cache_path() const override; |