From 243e6faffa712de8cd2adc20e7514ededa8a4a6b Mon Sep 17 00:00:00 2001 From: peace-maker Date: Fri, 20 Feb 2026 10:07:48 +0100 Subject: [PATCH] asm: try native binutils before fallback architectures (#2669) * asm: try native binutils before fallback architectures Some binutils builds support multiple architectures, like the x86_64 assembler supports i386 too in most package builds and vice versa. We support this by trying the other binutils as well when looking for the right tool. That support is optional though and there are packages that don't include the "cross" compilation. When assembling for the host's native architecture, we still prefer the explicitly named `x86_64-linux-gnu-as` instead of the native `as` binary. That native binary is tried as a last resort after looking for any other explictly named binary. If the fallback package is installed but compiled without the cross-compiler support, we'd still find the `i386-as` binary while looking for `x86_64-as` before trying the native `as` binary. That would fail to assemble. This patch moves the native `as` binary forward in the list to try it before checking the other fallback architecture ones. Fixes #2509 * Update CHANGELOG --- CHANGELOG.md | 4 +++- pwnlib/asm.py | 24 ++++++++++++++++-------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 656fc298..3c51998e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -112,6 +112,7 @@ The table below shows which release corresponds to each branch, and what date th - [#2629][2629] Add `terminate()` method to process class that sends SIGTERM - [#2643][2643] Refactor getdents.py, add support for SYS_getdents64 - [#2647][2647] packing: Add `overlap` to overlap structures easily +- [#2669][2669] asm: try native binutils before fallback architectures [2675]: https://github.com/Gallopsled/pwntools/pull/2675 [2652]: https://github.com/Gallopsled/pwntools/pull/2652 @@ -148,8 +149,9 @@ The table below shows which release corresponds to each branch, and what date th [2641]: https://github.com/Gallopsled/pwntools/pull/2641 [2646]: https://github.com/Gallopsled/pwntools/pull/2646 [2629]: https://github.com/Gallopsled/pwntools/pull/2629 -[2638]: https://github.com/Gallopsled/pwntools/pull/2643 +[2643]: https://github.com/Gallopsled/pwntools/pull/2643 [2647]: https://github.com/Gallopsled/pwntools/pull/2647 +[2669]: https://github.com/Gallopsled/pwntools/pull/2669 ## 4.15.0 (`stable`) diff --git a/pwnlib/asm.py b/pwnlib/asm.py index f56995e6..6a73c44e 100644 --- a/pwnlib/asm.py +++ b/pwnlib/asm.py @@ -188,31 +188,37 @@ def which_binutils(util, check_version=False): # Fix up pwntools vs Debian triplet naming, and account # for 'thumb' being its own pwntools architecture. - arches = [arch] + { + aliases = { 'thumb': ['arm', 'aarch64'], - 'i386': ['x86_64', 'amd64'], 'i686': ['x86_64', 'amd64'], - 'amd64': ['x86_64', 'i386'], + 'amd64': ['x86_64'], + 'loongarch64': ['loong64'], + }.get(arch, []) + + # Some binutils can support multiple architectures. Try them as fallbacks. + fallback_arches = { + 'i386': ['x86_64', 'amd64'], + 'amd64': ['i386'], 'arm': ['aarch64'], 'mips': ['mipsel'], 'mipsel': ['mips'], - 'mips64': ['mips', 'mipsel'], - 'mips64el': ['mipsel', 'mips'], + 'mips64': ['mips64el', 'mips', 'mipsel'], + 'mips64el': ['mips64', 'mipsel', 'mips'], 'powerpc64': ['powerpc'], 'sparc64': ['sparc'], 'riscv32': ['riscv64', 'riscv'], 'riscv64': ['riscv32', 'riscv'], - 'loongarch64': ['loong64'], }.get(arch, []) + arches = [arch] + aliases + fallback_arches # If one of the candidate architectures matches the native - # architecture, use that as a last resort. + # architecture, use that as a last resort before trying fallbacks. machine = platform.machine() machine = 'i386' if machine == 'i686' else machine try: with context.local(arch = machine): if context.arch in arches: - arches.append(None) + arches = [arch] + aliases + [None] + fallback_arches except AttributeError: log.warn_once("Your local binutils won't be used because architecture %r is not supported." % machine) @@ -225,6 +231,8 @@ def which_binutils(util, check_version=False): if platform.system() == 'Windows': utils = [util + '.exe'] + # Try the explicit tools for the target architecture first, + # then the native one optionally, then fallbacks. for arch in arches: for gutil in utils: # e.g. objdump