Skip to content

Commit 1458967

Browse files
mhuescht184256
authored andcommitted
fix(proot-termux): LLVM 21 build and runtime fixes
- Cross-prefixed readelf for loader-info.c generation - Loader ELF p_align binary patch (lld nmagic workaround) - AArch64 SP alignment in transfer_load_script (align-sp.patch)
1 parent 791384a commit 1458967

File tree

4 files changed

+69
-3
lines changed

4 files changed

+69
-3
lines changed

modules/environment/login/default.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ in
8787
prootStatic =
8888
let
8989
crossCompiledPaths = {
90-
aarch64-linux = "/nix/store/w9km5x8v4xma2wgqxpsx4jbr2kz7nk33-proot-termux-static-aarch64-unknown-linux-android-0-unstable-2025-10-19";
91-
x86_64-linux = "/nix/store/xpnf8vzswwaqmgxakcqhw8f5b4363rsh-proot-termux-static-x86_64-unknown-linux-android-0-unstable-2025-10-19";
90+
aarch64-linux = "/nix/store/0xjhdhcarb47yhhlgbjna3qn0cwl7gxh-proot-termux-static-aarch64-unknown-linux-android-0-unstable-2025-10-19";
91+
x86_64-linux = "/nix/store/qxnj7km4nqvk1fgbnb71afy9ma78c60i-proot-termux-static-x86_64-unknown-linux-android-0-unstable-2025-10-19";
9292
};
9393
in
9494
"${crossCompiledPaths.${targetSystem}}";

pkgs/proot-termux/align-sp.patch

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
commit 89ea8886e69cb175eee727c871b2251f1fc7aea1
2+
Author: Alexander Sosedkin <monk@unboiled.info>
3+
Date: Tue Feb 17 07:29:14 2026 +0100
4+
5+
Align SP to 16 bytes on AArch64
6+
7+
Reported-by: Michael Hueschen <m@mhueschen.space>
8+
9+
diff --git a/src/execve/exit.c b/src/execve/exit.c
10+
index f32d3ec..b12c574 100644
11+
--- a/src/execve/exit.c
12+
+++ b/src/execve/exit.c
13+
@@ -224,9 +224,14 @@ static int transfer_load_script(Tracee *tracee)
14+
15+
/* A padding will be appended at the end of the load script
16+
* (a.k.a "strings area") to ensure this latter is aligned to
17+
- * a word boundary, for sake of performance. */
18+
+ * a word boundary, for the sake of performance
19+
+ * (or 16 bytes since AArch64 needs SP to 16-bytes aligned). */
20+
padding_size = (stack_pointer - string1_size - string2_size - string3_size)
21+
+#ifdef ARCH_ARM64
22+
+ % 16;
23+
+#else
24+
% sizeof_word(tracee);
25+
+#endif
26+
27+
strings_size = string1_size + string2_size + string3_size + padding_size;
28+
string1_address = stack_pointer - strings_size;

pkgs/proot-termux/default.nix

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,26 @@ stdenv.mkDerivation {
3434
'#define HAS_LOADER_32BIT true' \
3535
""
3636
! (grep -F '#define HAS_LOADER_32BIT' src/arch.h)
37-
# don't wanna get a 128GB loader (LLVM 17->21 regression?)
37+
# LLVM 21's lld sets file_offset = vaddr for -Ttext=0x2000000000,
38+
# producing an 8 GB loader binary. Adding -n (nmagic) fixes the file
39+
# size but sets p_align=4, which Android kernels reject (EINVAL on
40+
# execve). Solution: link with -n, then binary-patch p_align to
41+
# 0x10000 (64 KB, safe for 4/16/64 KB page-size devices).
3842
substituteInPlace src/GNUmakefile --replace ",-Ttext" ",-n,-Ttext"
43+
# Patch p_align in the first Elf64_Phdr (LOAD) of the loader ELF.
44+
# Elf64_Ehdr is 64 bytes; Elf64_Phdr.p_align is at offset 48 within
45+
# the phdr → file offset 112. Written after cp, before strip.
46+
substituteInPlace src/GNUmakefile --replace \
47+
'$$(Q)cp $$< $$@' \
48+
'$$(Q)cp $$< $$@ && printf '"'"'\x00\x00\x01\x00\x00\x00\x00\x00'"'"' | dd of=$$@ bs=1 seek=112 count=8 conv=notrunc 2>/dev/null'
49+
# readelf is needed to generate loader-info.c (pokedata workaround offset).
50+
# The Makefile calls bare 'readelf' but only the cross-prefixed version exists.
51+
substituteInPlace src/GNUmakefile --replace "readelf -s" "${stdenv.cc.targetPrefix}readelf -s"
52+
# AArch64 requires 16-byte-aligned SP. proot's transfer_load_script sets
53+
# SP = stack_pointer − buffer_size, which may not be aligned. LLVM 21's
54+
# loader uses SP-relative addressing in _start, so misalignment → SIGBUS.
55+
# Fix: align SP down independently; keep x0 pointing to actual data.
56+
patch -p1 < ${./align-sp.patch}
3957
'';
4058
buildInputs = [ talloc ];
4159
patches = [ ./detranslate-empty.patch ];
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--- a/src/tracee/event.c
2+
+++ b/src/tracee/event.c
3+
@@ -668,6 +668,17 @@
4+
break;
5+
}
6+
7+
+ case SIGBUS: {
8+
+ siginfo_t siginfo = {};
9+
+ ptrace(PTRACE_GETSIGINFO, tracee->pid, NULL, &siginfo);
10+
+ note(tracee, WARNING, INTERNAL,
11+
+ "vpid %" PRIu64 ": SIGBUS si_code=%d si_addr=%p PC=0x%lx SP=0x%lx",
12+
+ tracee->vpid, siginfo.si_code, siginfo.si_addr,
13+
+ (unsigned long)peek_reg(tracee, CURRENT, INSTR_POINTER),
14+
+ (unsigned long)peek_reg(tracee, CURRENT, STACK_POINTER));
15+
+ break;
16+
+ }
17+
+
18+
default:
19+
/* Deliver this signal as-is,
20+
* unless we're chaining syscall. */

0 commit comments

Comments
 (0)