Hi everyone,
I’ve been trying to package some old i386 applications/games as AppImages, but I’m not satisfied with the current approach of targeting either x86_64 or i386 exclusively. In reality, if I bundle all the necessary i386 runtime libraries, the AppImage should run on an x86_64 system even without i386 support enabled. To achieve this, I need to modify the program’s rpath and interpreter to make it fully portable and work seamlessly with both 32-bit and 64-bit systems when double-clicked or executed.
However, when packaging this as an AppImage, a major issue arises: the hardcoded relative interpreter path (/lib/ld-linux.so.2). While I can use patchelf --set-interpreter to modify it, the interpreter path doesn’t accept environment variables like $ORIGIN (unlike rpath). For the main application binary, this isn’t a big deal since it can still handle . or .., but for the AppImage or AppRun, it’s a problem. The mount path changes every time, making it impossible to specify a fixed path for ld-linux.so.2 in AppRun.
The current dilemma is this: if I modify AppRun with patchelf, it won’t support dynamic paths. I’ve seen some experimental projects that attempt to address this, but unfortunately, they only support 64-bit architectures, so they’re not helpful for our case.
like this:https://github.com/corsix/polyfill-glibc/blob/main/docs/Relative_interpreter.md
If I abandon the binary AppRun and instead use a shell script named AppRun, the AppImage itself (as a binary) still hardcodes /lib/ld-linux.so.2. Of course, we could enable i386 libraries system-wide to ensure /lib/ld-linux.so.2 exists, but that clearly goes against the spirit of AppImage—the whole point of AppImage is to avoid installing dependencies, isn’t it?
This isn’t a problem report or a feature request—just a discussion to see if anyone has better ideas to make this work.
Personally, I think the solution lies in making AppRun dynamically recognize $APPDIR/lib/ld-linux.so.2 while ensuring the AppImage binary can still execute properly. But I’m not sure how to achieve that.
All reactions
Replies: 5 comments 2 replies
Hi @kero990, thanks for bringing up this interesting subject.
Indeed I have been looking for a way to use $ORIGIN to set the interpreter for a long time, didn't know about https://github.com/corsix/polyfill-glibc/blob/main/docs/Relative_interpreter.md, so thank you very much for mentioning it.
They write
The tool is currently only available for x86_64. If other architectures are of interest to you, open a GitHub issue so that we can gauge demand.
So I've done just that:
Maybe you'd like to give it a thumbs up?
As to your concrete issue, I don't fully understand what you are trying to accomplish, and how.
It should be possible to put a 32-bit binary (and libraries) into a 64-bit AppImage with no issues, if you bundle libc entirely (or use a static build). In fact, I have done it before to run 32-bit software on 64-bit machines.
Or are you saying you need your 32-bit binary (and libraries) in a 32-bit AppImage, and this is not running on a 64-bit machine for some reason?
In any case, please show the concrete script you are using to produce the AppImage. Thanks!
All reactions
the AppImage itself (as a binary) still hardcodes /lib/ld-linux.so.2
Are you talking about the appimage runtime? Use the static runtime in that case.
In any case if you are ok with changing the current working dir, the solution is having an AppRun script that changes the current working dir to the top level of the AppDir (usually the HERE var) and have a relative interpreter for the 32 and 64 bit binaries.
I think the solution lies in making AppRun dynamically recognize $APPDIR/lib/ld-linux.so.2 while ensuring the AppImage binary can still execute properly. But I’m not sure how to achieve that.
https://github.com/VHSgunzo/sharun
While the code has support for 32bit, including automatically separating 32bit libs from 64bit libs and checking the respective dynamic linker, sharun only has 64bit releases.
All reactions
the AppImage itself (as a binary) still hardcodes /lib/ld-linux.so.2
Are you talking about the appimage runtime? Use the static runtime in that case.
Which is the default nowadays anyway.
AppRun.c's AppRun binary should not be used by anyone randomly without knowing exactly what they do!
All reactions
-
😄 1
As to your concrete issue, I don't fully understand what you are trying to accomplish, and how.
sorry,It's possible that I have been too focused on detailing specifics while overlooking the description of requirements. Here's the situation: If I package all the i386 libraries (including libc and ld-linux, everything that's needed), this i386 package can run in a pure 64-bit environment, even if the system does not have i386 support enabled. In other words, this package can run on both i386 and x64 systems without requiring any modifications from the user.
However, I am attempting to package it as an AppImage, and here's where the issue arises: an AppImage is either i386 or x64; the appimage file can run on both 32-bit and 64-bit systems simultaneously, even though its content is fully capable of doing so.
The obstacle to achieving this lies in what I mentioned initially: both AppRun and the AppImage file are binary files, and they must have /lib/ld-linux.so.2 hard-coded. This linker must reside in /lib and not anywhere else, even if the AppImage itself already packages the linker. The binary files will only search for /lib/ld-linux.so.2, not the one included in the package.
In summary, I am seeking a method that allows a 32-bit AppImage to run on both 32-bit and 64-bit systems, to avoid distributing two packages with identical content. While the packaged content itself is capable of achieving this, the AppImage format currently does not support it.
All reactions
AppImage is either i386 or x64
Yep, that is true. This is a limitation of the ELF standard. Additions like FatELF never made it into the standard.
both AppRun and the AppImage file are binary files and they must have /lib/ld-linux.so.2 harcoded
Ok, two misunderstandings here.
First of all, your AppRun does not need to be binary. It could be a shell script deciding which ld-linux to call. If you built your application statically, it would run, too. (In case you use that AppRun file from this repository's release page: forget about it, it won't work, you better make it work without).
The current type-2 runtime is statically linked nowadays. You could just use the i386 runtime for your AppImage.
The binary files will only search for /lib/ld-linux.so.2, not the one included in the package.
Because it's not the binary that is searching for ld-linux (aka the loader), it is the kernel while trying to execute the AppImage runtime. You cannot control this from within the AppImage.
In summary, I am seeking a method that allows a 32-bit AppImage to run on both 32-bit and 64-bit systems, to avoid distributing two packages with identical content. While the packaged content itself is capable of achieving this, the AppImage format currently does not support it.
... and it never will, the way, e.g., macOS does. But you should nowadays be able to ship an i386 AppImage to both audiences. Please try with the appimagetool from https://github.com/AppImage/appimagetool.
All reactions
P.S.: In theory, your i386 AppImage then just work on x86_64 as well, maybe with some memory limitations, but it should work right away if you bundle the loader anyway. No need to package 64-bit binaries in addition unless you need some runtime advantage (e.g., being able to address more memory).
All reactions
@probonopd I'd appreciate if you could convert such issues to discussions right away. That makes them easier to find.
Also, we should consider finally taking down the binaries from this release page. They can be hosted somewhere for archiving, but too many people end up using legacy technology.