Box32: x86 LD_PRELOAD dropped as ELFCLASS32 inside a system() call - expected? #3976
-
|
Question about Box32 + LD_PRELOAD inside a system() call (not a bug report, trying to understand expected behaviour) Setup: Retroid Pocket 6 (Snapdragon 8 Gen 2, arm64), Android 13, no root, Termux + proot Debian Trixie. box64 v0.4.3 built from source with BOX32 enabled. I'm running a 32-bit x86 program through a 32-bit x86 loader that injects a hook library via LD_PRELOAD (it's an arcade loader, but I don't think the specifics matter for the question). Everything is launched through box64. Both the hook library and the target binary are confirmed 32-bit x86 - I checked the ELF headers directly, both are 7f 45 4c 46 01 ... with e_machine = EM_386. What happens: the loader launches fine under box64, reads its config, then spawns the target. At that point I get this in the log (BOX64_LOG=2): [BOX32] 7589|0x40004761: Calling system (3081E09C, 3081EC9C, 00000000...) =>ERROR: ld.so: object 'mylib.so' from LD_PRELOAD cannot be preloaded (wrong ELF class: ELFCLASS32): ignored then the target dies with a bare: Illegal instruction I had BOX64_SHOWSEGV=1 set and it produced no unhandled-opcode message or signal dump, just the env echo and then the bare "Illegal instruction". What I'm trying to understand: When a process running under Box32 makes a system() call with LD_PRELOAD set to a 32-bit x86 .so, is Box32 expected to handle that preload, or is it expected to be passed to the host (arm64) linker, which then rejects it as ELFCLASS32? The [BOX32] tag on the line makes me think Box is at least aware of the call, but the ELFCLASS32 rejection looks like the host linker talking. I can attach the full BOX64_LOG=2 log and BOX64_DLSYM_ERROR output. Mainly I want to know whether this is expected Box32 behaviour and a known limitation, or whether I've set something up wrong. Thanks for any pointers. |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 2 replies
-
|
While the |
Beta Was this translation helpful? Give feedback.
-
|
Also, using an x86 or x86_64 library as a preload libraries to load an native program is also not supported (and not planned to be supported). |
Beta Was this translation helpful? Give feedback.
-
|
Thank you, that's the missing piece - it explains the bare SIGILL perfectly. The loader launches the game via system(), so box64 never wraps it, and since this is rootless Termux/proot there's no binfmt_misc registered to catch the x86 binary either. So the native CPU was just being handed x86 code directly, which is the illegal instruction. The game was never actually running under box64 - that's why SHOWSEGV had nothing to say. I'd been chasing the preload and the recompiler when neither was ever in the picture. That also makes it clear why this works on a normal Linux install (binfmt routes the system() call through box64) and why native Linux on the device would be the clean fix. For anyone who finds this later: the two structural blockers on rootless Android are (1) system() isn't wrapped and there's no binfmt to fall back on, and (2) x86 preload into a native program isn't supported. A loader using execve instead of system() would sidestep the first, since that path is wrapped - might be worth raising with the loader project as an Android-compatibility option rather than anything box64 needs to change. Out of interest, is wrapping system() something that's ever been considered, or is the binfmt-fallback assumption deliberate? Not asking for a feature - just trying to understand whether the execve route is the only realistic angle for rootless setups. Either way, thanks for the clear answer, it's saved me a lot of guessing. |
Beta Was this translation helpful? Give feedback.
While the
execvfamilly of library calls are wrapped and will inject a call to box64 if the target program is x86/x86_64, thesystemfunction is not, and will just call programs as-is, relying on binfmt to inject box64 for x86/x86_64 type binaries.