Skip to content

Use an .init_array function to capture argc/argv on Linux. #78854

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

grynspan
Copy link
Contributor

Per the ELF specification, the .init_array section contains a list of functions that need to be called before main() to initialize a library (i.e. libSwiftCore.so). The functions in this section take the initial values of argc, argv, and environ as arguments. This gives us an opportunity to capture/copy these values before main() is called in a way that may be more reliable than the current "inspect the stack" mechanism used on Linux (and derived platforms such as Android.)

Per the ELF specification, the `.init_array` section contains a list of
functions that need to be called before `main()` to initialize a library (i.e.
libSwiftCore.so). The functions in this section take the initial values of
`argc`, `argv`, and `environ` as arguments. This gives us an opportunity to
capture/copy these values before `main()` is called in a way that may be more
reliable than the current "inspect the stack" mechanism used on Linux (and
derived platforms such as Android.)
@grynspan grynspan added Linux Platform: Linux standard library Area: Standard library umbrella runtime The Swift Runtime Android Platform: Android labels Jan 23, 2025
@grynspan grynspan self-assigned this Jan 23, 2025
@grynspan
Copy link
Contributor Author

@swift-ci test

@Azoy
Copy link
Contributor

Azoy commented Jan 23, 2025

cc @al45tair

@al45tair
Copy link
Contributor

al45tair commented Jan 23, 2025

The functions in this section take the initial values of argc, argv, and environ as arguments.

Sadly, that is not true. Musl doesn't pass argc, argv or environ to the functions in this section. I think doing so is a GNU extension; I believe Bionic does pass these arguments. I don't know about other C libraries on other ELF platforms.

@grynspan
Copy link
Contributor Author

Well, for the sake of documenting the implementation if it ever becomes viable… here ya go.

@grynspan
Copy link
Contributor Author

Huh. This actually passed on Linux. I wasn't expecting that… @al45tair does this mean we don't have test coverage of the edge cases you mentioned?

@al45tair
Copy link
Contributor

@al45tair does this mean we don't have test coverage of the edge cases you mentioned?

Indeed, we don't. We could do with more testing of the Static SDK for Linux; there was some talk at one point of building programs from the compatibility test suite, and I think @justice-adams-apple did a little bit of work on that, but we don't have a regular job doing that (as far as I know) and we don't have anything during PR testing either.

@grynspan
Copy link
Contributor Author

Do we know at the point this file is compiled whether we're using Glibc or Musl? If not, we could set it up so it tries this first, but if the args are empty, we fall back to the existing code path. Or perhaps this is sufficient to cover those other cases, and we really just need this and the older "read from /proc" as a fallback?

@grynspan
Copy link
Contributor Author

@al45tair ping :)

@al45tair
Copy link
Contributor

Do we know at the point this file is compiled whether we're using Glibc or Musl?

We do, yes.

If not, we could set it up so it tries this first, but if the args are empty, we fall back to the existing code path. Or perhaps this is sufficient to cover those other cases, and we really just need this and the older "read from /proc" as a fallback?

This isn't sufficient because of the combination of the Rosetta bug and Musl. That's why I picked the admittedly baroque scheme that is in there now — which only fails when someone changes the environment from a constructor function. The only place I know of where someone was doing that has now been fixed, FWIW (they also thought doing that was crazy but were unable to do anything else because of a problem with an Intel driver).

The right fix for all of this is to capture the arguments when entering the main function, as that's the only place you can guarantee that they are valid. That would require changing the compiler's codegen to emit something suitable at the entry point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Android Platform: Android Linux Platform: Linux runtime The Swift Runtime standard library Area: Standard library umbrella
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants