Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified app/src/main/jniLibs/arm64-v8a/libproot-loader.so
Binary file not shown.
Binary file modified app/src/main/jniLibs/arm64-v8a/libproot-loader32.so
Binary file not shown.
Binary file modified app/src/main/jniLibs/arm64-v8a/libproot.so
Binary file not shown.
Binary file modified app/src/main/jniLibs/armeabi-v7a/libproot-loader.so
Binary file not shown.
Binary file modified app/src/main/jniLibs/armeabi-v7a/libproot.so
Binary file not shown.
Binary file modified app/src/main/jniLibs/x86/libproot-loader.so
Binary file not shown.
Binary file modified app/src/main/jniLibs/x86/libproot.so
Binary file not shown.
Binary file modified app/src/main/jniLibs/x86_64/libproot-loader.so
Binary file not shown.
Binary file modified app/src/main/jniLibs/x86_64/libproot-loader32.so
Binary file not shown.
Binary file modified app/src/main/jniLibs/x86_64/libproot.so
Binary file not shown.
102 changes: 93 additions & 9 deletions native/build-proot.sh
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,25 @@ build_proot() {
build_talloc

echo "==> [$ABI] proot $PROOT_VERSION"
# 32-bit ABIs: bionic's ARM32 static-TLS layout check (StaticTlsLayout in
# bionic/libc/bionic/bionic_elf_tls.cpp) aborts when the executable's
# PT_TLS is underaligned, and it checks p_align AND the skew
# (p_vaddr % p_align) together. A plain NDK link emits p_align=8 with a
# 16-aligned vaddr, which aborts on-device with "executable's TLS
# segment is underaligned ... needs to be at least 32 for ARM Bionic".
# Hand-patching the program header cannot fix the vaddr half: p_vaddr
# also feeds init_ptr, the address bionic copies the TLS template from,
# so vaddr must stay where the section really is. Only a re-link with
# a script that START-aligns .tdata at 32 does it. (i686 needs no fix
# — bionic has no TLS gate on i386 — but the same script keeps the
# build uniform.)
TLS_SCRIPT=""
case "$ABI" in
armeabi-v7a) TLS_SCRIPT="$SCRIPT_DIR/proot-tls-align-armv7a.ld" ;;
x86) TLS_SCRIPT="$SCRIPT_DIR/proot-tls-align-i686.ld" ;;
esac
local tls_ldflags=""
[ -n "$TLS_SCRIPT" ] && tls_ldflags=" -Wl,-T$TLS_SCRIPT"
if [ ! -d "$work/proot" ]; then
git clone "$PROOT_REPO" "$work/proot"
fi
Expand All @@ -162,14 +181,15 @@ import re, sys
page = sys.argv[1]
p = "GNUmakefile"
s = open(p).read()
new = re.sub(
r'(LOADER_LDFLAGS\$1 \+= -static -nostdlib )',
r'\1-Wl,-z,max-page-size=' + page + ' ',
s,
)
if new == s:
sys.exit("ERROR: could not inject loader page size into GNUmakefile")
open(p, "w").write(new)
if "-Wl,-z,max-page-size=" not in s:
new = re.sub(
r'(LOADER_LDFLAGS\$1 \+= -static -nostdlib )',
r'\1-Wl,-z,max-page-size=' + page + ' ',
s,
)
if new == s:
sys.exit("ERROR: could not inject loader page size into GNUmakefile")
open(p, "w").write(new)
PYEOF
cat > loader/loader-fix.h << 'EOF'
#ifndef PATH_MAX
Expand All @@ -178,12 +198,76 @@ PYEOF
EOF
CC="$CC" AR="$AR" STRIP="$STRIP" OBJCOPY="$OBJCOPY" OBJDUMP="$OBJDUMP" \
CFLAGS="-I$TALLOC_INSTALL/include -O2 -fPIC -DARG_MAX=131072 -Wno-implicit-function-declaration -Wno-implicit-int" \
LDFLAGS="-L$TALLOC_INSTALL/lib -static -Wl,-z,max-page-size=$PAGE_SIZE" \
LDFLAGS="-L$TALLOC_INSTALL/lib -static -Wl,-z,max-page-size=$PAGE_SIZE$tls_ldflags" \
make -j"$(nproc)"
)

echo "==> [$ABI] installing"
install -m 0755 "$work/proot/src/proot" "$OUTPUT_DIR/$ABI/libproot.so"

# TLS alignment fix. bionic's static-TLS layout check exists only on ARM:
# "executable's TLS segment is underaligned ... needs to be at least 32
# for ARM Bionic / 64 for ARM64 Bionic". 64-bit: the plain link already
# emits a 64-aligned vaddr, so patching p_align 8 -> 64 in the program
# header is safe (init_ptr is vaddr-based and stays correct). i386/x86_64
# have no gate at all; the patch below is a no-op there.
case "$ABI" in
arm64-v8a|x86_64)
# 64-bit: native layout has TLS vaddr 64-aligned, patch p_align to 64
python3 - "$OUTPUT_DIR/$ABI/libproot.so" "$ABI" <<'PYEOF'
import struct, sys
path, abi = sys.argv[1], sys.argv[2]
data = bytearray(open(path, "r+b").read())
assert data[:4] == b"\x7fELF"
cls = data[4]
F = "<Q"
phoff = struct.unpack_from("<Q", data, 0x20)[0]
entsize = struct.unpack_from("<H", data, 0x36)[0]
phnum = struct.unpack_from("<H", data, 0x38)[0]
patched = False
for i in range(phnum):
off = phoff + i * entsize
p_type = struct.unpack_from("<I", data, off)[0]
if p_type not in (7, 14):
continue
vaddr = struct.unpack_from("<Q", data, off + 16)[0]
align = struct.unpack_from("<Q", data, off + 48)[0]
if align < 64:
if vaddr % 64 != 0:
sys.exit(f"ERROR: PT_TLS vaddr 0x{vaddr:x} is not 64-aligned")
struct.pack_into("<Q", data, off + 48, 64)
print(f"Patched PT_TLS p_align {align} -> 64 for {abi}")
patched = True
if patched:
open(path, "wb").write(bytes(data))
if not patched:
print("No PT_TLS phdr patched (already aligned or not found)")
PYEOF
;;
armeabi-v7a|x86)
# 32-bit: TLS alignment was baked in at link time (-Wl,-T$TLS_SCRIPT).
# Verify, don't patch: PT_TLS must have p_align 32 and a 32-aligned
# vaddr, or bionic's ARM32 static-TLS check aborts the binary.
python3 - "$OUTPUT_DIR/$ABI/libproot.so" "$ABI" <<'PYEOF'
import struct, sys
path, abi = sys.argv[1], sys.argv[2]
data = open(path, "rb").read()
assert data[:4] == b"\x7fELF" and data[4] == 1
phoff = struct.unpack_from("<I", data, 0x1C)[0]
entsize = struct.unpack_from("<H", data, 0x2A)[0]
phnum = struct.unpack_from("<H", data, 0x2C)[0]
for i in range(phnum):
off = phoff + i * entsize
if struct.unpack_from("<I", data, off)[0] != 7:
continue
vaddr = struct.unpack_from("<I", data, off + 8)[0]
align = struct.unpack_from("<I", data, off + 28)[0]
if align != 32 or vaddr % 32 != 0:
sys.exit(f"ERROR: {abi} PT_TLS p_align={align} vaddr=0x{vaddr:x} (need p_align=32, vaddr%32==0)")
print(f"{abi}: PT_TLS p_align={align} vaddr=0x{vaddr:x} OK")
PYEOF
;;
esac
install -m 0755 "$work/proot/src/loader/loader" "$OUTPUT_DIR/$ABI/libproot-loader.so"
if [ -f "$work/proot/src/loader/loader-m32" ]; then
install -m 0755 "$work/proot/src/loader/loader-m32" "$OUTPUT_DIR/$ABI/libproot-loader32.so"
Expand Down
112 changes: 112 additions & 0 deletions native/proot-tls-align-armv7a.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/* RedTerm: proot TLS fix for 32-bit ARM (armeabi-v7a).
*
* bionic's static-TLS layout check (StaticTlsLayout::reserve_exe_segment_and_tcb,
* bionic/libc/bionic/bionic_elf_tls.cpp) aborts an ARM32 executable when
* align_checked(2*word) != align_checked(tcb_size_post)
* where the check folds in both p_align AND the skew p_vaddr % p_align.
* A plain NDK link emits PT_TLS p_align=8 with a 16-aligned p_vaddr, which
* aborts with "executable's TLS segment is underaligned ... needs to be at
* least 32 for ARM Bionic".
*
* The fix is to make the linker START-align .tdata/.tbss at 32, so the
* emitted PT_TLS has p_align=32 and p_vaddr % 32 == 0 (skew 0). Patching the
* program header by hand is NOT enough: p_vaddr also feeds init_ptr, the
* address bionic memcpies the TLS template from, so vaddr and the section's
* real location must stay equal, which only a relink can guarantee.
*
* This is a full layout script (plain NDK linking produced base 0x10000,
* 16 KB-aligned LOADs); it is lld-compatible (no GNU-only constants).
*/
SECTIONS
{
. = 0x10000;
.text : {
KEEP(*(.text.startup))
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.hot .text.hot.*)
*(SORT(.text.sorted.*))
*(.text .stub .text.* .gnu.linkonce.t.*)
*(.gnu.warning)
*(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
}
.fini : { KEEP(*(SORT_NONE(.fini))) }
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
.ARM.exidx : {
PROVIDE_HIDDEN (__exidx_start = .);
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
PROVIDE_HIDDEN (__exidx_end = .);
}
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.sframe : ONLY_IF_RO { KEEP (*(.sframe)) *(.sframe.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
.gnu_except_table : ONLY_IF_RO { *(.gnu_except_table .gnu_except_table.*) }
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
.note.build-id : { *(.note.build-id) }
.note.GNU-stack : { *(.note.GNU-stack) }
.note.gnu.property : { *(.note.gnu.property) }
.note.ABI-tag : { *(.note.ABI-tag) }
.note.package : { *(.note.package) }
.note.dlopen : { *(.note.dlopen) }
.note.netbsd.ident : { *(.note.netbsd.ident) }
.note.openbsd.ident : { *(.note.openbsd.ident) }
/* Align the data segment to the 16 KB page size (see -z max-page-size). */
. = ALIGN(16384);
.tdata : ALIGN(32) {
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
}
.preinit_array : {
PROVIDE_HIDDEN (__preinit_array_start = .);
*(.preinit_array)
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array : {
PROVIDE_HIDDEN (__init_array_start = .);
*(SORT_BY_INIT_PRIORITY(.init_array .init_array.*))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array : {
PROVIDE_HIDDEN (__fini_array_start = .);
*(SORT_BY_INIT_PRIORITY(.fini_array .fini_array.*))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.data.rel.ro : {
*(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.*)
*(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*)
}
.data.rel.ro.local : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got.plt) *(.got) }
.data : {
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .;
PROVIDE (edata = .);
__bss_start = .;
.bss : {
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(32);
}
_end = .;
PROVIDE (end = .);
__bss_end__ = .;
.stab : { *(.stab) }
.stabstr : { *(.stabstr) }
.stab.excl : { *(.stab.excl) }
.stab.exclstr : { *(.stab.exclstr) }
.stab.index : { *(.stab.index) }
.stab.indexstr : { *(.stab.indexstr) }
.comment : { *(.comment) }
.note.android.ident : { *(.note.android.ident) }
}
83 changes: 83 additions & 0 deletions native/proot-tls-align-i686.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/* RedTerm: proot TLS fix for i386 (i686 / "x86").
*
* bionic's static-TLS check has no underalignment gate on i386 (the ARM-only
* abi_tpoff/actual_tpoff comparison in bionic/libc/bionic/bionic_elf_tls.cpp),
* so a plain link works here; this script exists for uniformity with the
* armeabi-v7a build and to START-align .tdata/.tbss at 32 so the emitted
* PT_TLS stays consistent with the ARM build.
*
* Full layout script matching the plain NDK link (base 0x400000, 16 KB
* page-aligned LOADs); lld-compatible (no GNU-only constants).
*/
SECTIONS
{
. = 0x400000;
.text : {
KEEP(*(.text.startup))
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.hot .text.hot.*)
*(SORT(.text.sorted.*))
*(.text .stub .text.* .gnu.linkonce.t.*)
*(.gnu.warning)
}
.fini : { KEEP(*(SORT_NONE(.fini))) }
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.sframe : ONLY_IF_RO { KEEP (*(.sframe)) *(.sframe.*) }
.note.GNU-stack : { *(.note.GNU-stack) }
.note.gnu.property : { *(.note.gnu.property) }
.note.ABI-tag : { *(.note.ABI-tag) }
.note.android.ident : { *(.note.android.ident) }
/* Align the data segment to the 16 KB page size (see -z max-page-size). */
. = ALIGN(16384);
.tdata : ALIGN(32) {
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
}
.preinit_array : {
PROVIDE_HIDDEN (__preinit_array_start = .);
*(.preinit_array)
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array : {
PROVIDE_HIDDEN (__init_array_start = .);
*(SORT_BY_INIT_PRIORITY(.init_array .init_array.*))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array : {
PROVIDE_HIDDEN (__fini_array_start = .);
*(SORT_BY_INIT_PRIORITY(.fini_array .fini_array.*))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.data.rel.ro : {
*(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.*)
*(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*)
}
.data.rel.ro.local : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.got.plt) }
.data : {
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .;
PROVIDE (edata = .);
__bss_start = .;
.bss : {
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(32);
}
_end = .;
PROVIDE (end = .);
__bss_end__ = .;
.comment : { *(.comment) }
}
Loading