diff --git a/gnu/local.mk b/gnu/local.mk index c7db93ecd6..8b6ebc51f4 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -1215,6 +1215,7 @@ dist_patch_DATA = \ %D%/packages/patches/dvdbackup-with-libdvdread-6.1.0+.patch \ %D%/packages/patches/dvd+rw-tools-add-include.patch \ %D%/packages/patches/dwarves-threading-reproducibility.patch \ + %D%/packages/patches/e9patch-zydis-4.1-compat.patch \ %D%/packages/patches/efitools-riscv64-support.patch \ %D%/packages/patches/efivar-fix-fprint-format.patch \ %D%/packages/patches/elastix-1404.patch \ diff --git a/gnu/packages/patches/e9patch-zydis-4.1-compat.patch b/gnu/packages/patches/e9patch-zydis-4.1-compat.patch new file mode 100644 index 0000000000..93621b687e --- /dev/null +++ b/gnu/packages/patches/e9patch-zydis-4.1-compat.patch @@ -0,0 +1,80 @@ +commit c02dd23b12fd687a041ab3b872b3f989cd1342dc +Author: Nguyễn Gia Phong +Date: 2024-11-18 15:13:17 +0900 + + Make compatible with Zydis 4.1 + + This Zydis version is more explicit in formatting + lea instructions in Intel format. + + The hunk adding sqrtss is due to a bug in Zydis: + https://github.com/zyantific/zydis/issues/542 + + For this reason, E9Patch is not open to updating Zydis. + +diff --git a/src/e9tool/e9x86_64.cpp b/src/e9tool/e9x86_64.cpp +index 6a7f5cff3692..03eb3a41dd66 100644 +--- a/src/e9tool/e9x86_64.cpp ++++ b/src/e9tool/e9x86_64.cpp +@@ -152,8 +152,7 @@ void e9tool::getInstrInfo(const ELF *elf, const Instr *I, InstrInfo *info, + ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT]; + + ZyanStatus result = ZydisDecoderDecodeFull(&decoder, +- elf->data + I->offset, I->size, D, operands, ZYDIS_MAX_OPERAND_COUNT, +- 0); ++ elf->data + I->offset, I->size, D, operands); + if (!ZYAN_SUCCESS(result) || I->size != D->length || + D->operand_count > sizeof(info->op) / sizeof(info->op[0])) + error("failed to decompress instruction at address 0x%lx; decode " +@@ -336,7 +335,7 @@ void e9tool::getInstrInfo(const ELF *elf, const Instr *I, InstrInfo *info, + info->string.section = elf->strs + shdr->sh_name; + result = ZydisFormatterFormatInstruction(&formatter, D, operands, + D->operand_count_visible, info->string.instr, +- sizeof(info->string.instr)-1, I->address); ++ sizeof(info->string.instr)-1, I->address, ZYAN_NULL); + if (!ZYAN_SUCCESS(result)) + error("failed to decompress instruction at address 0x%lx; " + "formatting failed", I->address); +diff --git a/test/regtest/print_intel.exp b/test/regtest/print_intel.exp +index ae91f44..9bdbe0f 100644 +--- a/test/regtest/print_intel.exp ++++ b/test/regtest/print_intel.exp +@@ -24,14 +24,14 @@ jmp 0xa000163 + call 0xa000168 + jmp 0xa00016d + jmp 0xa000177 +-lea r10, [rip+0x14] ++lea r10, qword ptr [rip+0x14] + push r10 + push r11 + mov rcx, 0xffffffffffff8889 + jmp qword ptr [rsp+rcx*1+0x777f] + call 0xa0001b5 + add rsp, 0x8 +-lea rdx, [rip+0x2] ++lea rdx, qword ptr [rip+0x2] + call rdx + pop r14 + add r9, 0x6 +@@ -85,7 +85,7 @@ xor eax, eax + inc eax + mov edi, eax + inc rdi +-lea rsi, [rip+0x54] ++lea rsi, qword ptr [rip+0x54] + mov rdx, 0x7 + syscall + PASSED +diff --git a/test/regtest/same_op_2.exp b/test/regtest/same_op_2.exp +index f99033a..45790b8 100644 +--- a/test/regtest/same_op_2.exp ++++ b/test/regtest/same_op_2.exp +@@ -12,6 +12,7 @@ shl $0x7, %rdi + sar $0x3, %rdi + pxor %xmm0, %xmm0 + cvtsi2ss %rax, %xmm0 ++sqrtss %xmm0, %xmm1 + xor %esi, %esi + xor %eax, %eax + PASSED + diff --git a/gnu/packages/patchutils.scm b/gnu/packages/patchutils.scm index 52979779f9..b980359edc 100644 --- a/gnu/packages/patchutils.scm +++ b/gnu/packages/patchutils.scm @@ -34,6 +34,8 @@ #:use-module (gnu packages compression) #:use-module (gnu packages databases) #:use-module (gnu packages django) + #:use-module (gnu packages elf) + #:use-module (gnu packages engineering) #:use-module (gnu packages file) #:use-module (gnu packages freedesktop) #:use-module (gnu packages gawk) @@ -44,6 +46,7 @@ #:use-module (gnu packages gtk) #:use-module (gnu packages less) #:use-module (gnu packages mail) + #:use-module (gnu packages markup) #:use-module (gnu packages ncurses) #:use-module (gnu packages ocaml) #:use-module (gnu packages package-management) @@ -56,6 +59,7 @@ #:use-module (gnu packages text-editors) #:use-module (gnu packages time) #:use-module (gnu packages version-control) + #:use-module (gnu packages vim) #:use-module (gnu packages xml) #:use-module (gnu packages) #:use-module (guix build-system glib-or-gtk) @@ -121,6 +125,59 @@ using semantic patches in the @acronym{SmPL, Semantic Patch Language} for specifying desired matches and transformations in the C code.") (license license:gpl2)))) +(define-public e9patch + (package + (name "e9patch") + (version "1.0.0") + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/GJDuck/e9patch") + (commit (string-append "v" version)))) + (file-name (git-file-name name version)) + (sha256 + (base32 "1bgv05fnz0kfzpyikadp96zrr83214lk2nx82jpmlv9dq0lhxccq")) + ;; E9Patch is sensitive to Zydis version, including the latter's bugs: + ;; https://github.com/GJDuck/e9patch/pull/94#issuecomment-2525069952 + (patches (search-patches "e9patch-zydis-4.1-compat.patch")) + (modules '((guix build utils))) + ;; The following snippet is also for Zydis 4.1 compatibility. + ;; The patch replaces a single line in 43 files, producing a giant diff: + ;; https://github.com/GJDuck/e9patch/pull/93.patch + (snippet + #~(begin + (substitute* (find-files "test/regtest" "\\.exp$") + (("\\$0x8877665544332211") + "$-0x778899aabbccddef")) + ;; The regular expression to test is .*a.*, + ;; matching the number produced by the substitution above. + (substitute* "test/regtest/not_regex.exp" + ((".*\\$-0x778899aabbccddef.*") + "")))))) + (build-system gnu-build-system) + (arguments + (list + #:phases + #~(modify-phases %standard-phases + (delete 'configure)) + #:make-flags + #~(list (string-append "CC=" #$(cc-for-target)) + (string-append "PREFIX=" #$output)))) + (native-inputs (list markdown xxd)) + (inputs (list elfutils zycore zydis zlib)) + (home-page "https://github.com/GJDuck/e9patch") + (synopsis "Static binary rewriting tool") + (description + "E9Patch is a static binary rewriting tool for x86-64 ELF binaries, +both executables and shared objects. The patched binaries can be used +in place of the original, without requiring additional runtime dependencies. +Binary patches can be defined through a high-level interface, which focuses +on ease of use, or low-level interfaces, which provide additional flexibility +and allow optimizations for performance.") + (license (list license:expat ;src/e9patch/e9loader_*.cpp + license:gpl3+)))) ;rest + (define-public patchutils (package (name "patchutils")