-
-
Notifications
You must be signed in to change notification settings - Fork 615
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Loaders rewrite argv[0] for old binaries #1170
Conversation
For this to work, a loader has to be able to tell the difference between an ‘old’ and a ‘new’ binary. This is achieved via a repurposing of ELF’s e_flags field. We previously tried to use the padding in e_ident for it, but binutils was resetting it to zero in e.g. strip. This introduces one new ELF flag for cosmopolitan binaries. It is called `EF_APE_MODERN`, and it is bit 1. It should now be safe to install the ape loader binfmt registration with the `P` flag.
Tested on XnuSilicon and Linux x86_64. A printargs without the new flag gets its argv[0] changed, whereas a printargs with the new flag gets it preserved. |
The `ape -` variant with no arguments provides no way to shim in argv[0] so the loader had no way to tell the binary what its path was. This is a long-standing bug that looks like it has existed for as long as `ape -`, and old loaders would, I guess, just overwrite the sentinel NULL that is by convention the beginning and the end of a zero-length argv. From the vantage point of TryElf I can't see a really good solution so I just check for argc of 0 and let things be weird if a binary is run like that. This is only relevant with older binaries (as of jart#1170, those that don't set `EF_APE_MODERN`.)
We choose 0x101ca75, "lol cat 5". Also makes the argc check more explicit and moves the flags to their own section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I had noticed this before, but didn't comment. It seems the
To be actually safe, shouldn't our magic number when masked at least be limited to the unused bits in the above description? IMO, there would be a higher probability of not running into an intersection, which is what we're trying to accomplish with this change? If that were agreed, then a single masked bit might be best. Hopefully I'm not missing something here. Thank you! |
I mean, empirically, it works fine on my raspberry pi with the value we have now. None of these seem to actually be used; the linux kernel just straight-up ignores it. |
We'll find out in a moment if FreeBSD ARM cares about once I run it on fleet. |
Searching FreeBSD source for EF_ARM_ shows that the Otherwise, it appears that the Does all this matter? Probably not, just an FYI. |
I guess if needs be we can always just shift to the top half of the word. |
There are plenty of other ways of signaling that we are a new-school binary, just this seems like one of the most convenient if we can get away with it. |
A quick look at RPi source seems to show most of the
Since Cosmo doesn't care about 32-bit binaries, ORing in 0x100000000 would seem an easy way of ignoring all the other bits while remaining compatible, should any of this matter for Cosmo-created APE binaries typically run on desktops. |
For this to work, a loader has to be able to tell the difference between
an ‘old’ and a ‘new’ binary. This is achieved via a repurposing of ELF’s
e_flags field. We previously tried to use the padding in e_ident for it,
but binutils was resetting it to zero in e.g. strip.
This introduces one new ELF flag for cosmopolitan binaries. It is called
`
EF_APE_MODERN
`, and it is bit 1.It should now be safe to install the ape loader binfmt registration with
the `
P
` flag.