Skip to content

Add a static-PIE entry point and converter for Linux tsc - #65122

Draft
Jake Bailey (jakebailey) wants to merge 3 commits into
microsoft:mainfrom
jakebailey:pie
Draft

Jake Bailey (jakebailey) wants to merge 3 commits into
microsoft:mainfrom
jakebailey:pie

Conversation

@jakebailey

Copy link
Copy Markdown
Member

This is absolutely diabolical and I don't think I want to merge this, but one reason we can't really do -buildmode=pie is because we don't want to depend on libc, whose dynamic loader is literally hardcoded in the binary (boo).

But, I of course asked copilot "can we somehow patch a Go produced binary to make it PIE" and it came up with this idea, to build with -buildmode=pie, then patch the output to make it not use the hardcoded one but a function inside the binary itself, as Go doesn't actually use any complicated relocations.

This is exactly what gcc -static-pie or glibc --enable-static-pie or musl do.

I'm wondering if this is something that could be upstreamed, because it's quite interesting. But I'm opening the PR just to have it anyway.

We are required to ship position-independent executables. Go's
internal linker can build a PIE without cgo on several Linux
architectures, but the result names the glibc dynamic loader as its
interpreter, so it no longer starts on musl systems like Alpine, in
distroless images, or on NixOS, all of which run today's static
binaries fine.

Go-linked PIEs only need R_*_RELATIVE relocations and set up their own
TLS, so the loader has very little to do. Link a small entry point into
tsc that does that work itself, and add a tool that removes PT_INTERP
and points the ELF entry at it, producing a static-PIE that runs on any
Linux system.
On linux amd64, arm64, loong64, ppc64le, and s390x, Go can link a PIE
without an external linker, so build those as PIE with BIND_NOW and
convert them to static-PIE to keep them portable across libcs. Other
Linux targets would need an external linker for PIE and stay as they
are; Windows, macOS, and Android binaries are already PIE.
@typescript-automation typescript-automation Bot added Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug labels Nov 3, 2026
The converter rejected a fixed list of things it knew needed a dynamic
loader, so anything new that a future Go linker emits for the loader
to act on (a hardening property note, a new relocation format) would
have been silently dropped along with PT_INTERP. Accept only the
program headers, dynamic tags, and flag bits that Go emits today and
that the entry point fully handles, so such a change fails the build
instead.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant