Description
Go version:
go version devel go1.23-5f5e9f4ff1 Tue May 7 18:48:48 2024 +0000 linux/amd64
This problem happens for Go 1.23 (tip), but is not applicable for previous versions.
It appears that a recent change to the linker to enable full RELRO triggers some unpleasant behavior when Go programs are processed with "strip" (the binutils tool) for ELF targets. It should be noted that the problem only crops up for -buildmode=pie
binaries.
The change in question is CL 473495, which moves the .got
and .dynamic
sections from writable data into .data.rel.ro
when PIE buildmode is enabled (note that this change was initially rolled back and then rolled forward again in CL 571417). The resulting Go binaries execute properly, but something in the way they are constructed triggers a bug in the binutils version of strip
. Here is an example to demonstrate:
$ git clone https://go.googlesource.com/tools
...
$ cd tools/gopls
$ go build -o gopls.exe -trimpath -buildmode=pie
$ strip --version
GNU strip (GNU Binutils for Debian) 2.41.90.20240122
...
$ strip -o bad.exe gopls
strip: bad.exe: section .got lma 0x165c728 adjusted to 0x165c880
strip: bad.exe: section .dynamic lma 0x165c740 adjusted to 0x165c888
strip: bad.exe: section .data.rel.ro.typelink lma 0x165c880 adjusted to 0x165c9c8
strip: bad.exe: section .data.rel.ro.itablink lma 0x1663aa0 adjusted to 0x1663bdc
strip: bad.exe: section .data.rel.ro.gosymtab lma 0x1666230 adjusted to 0x166636c
strip: bad.exe: section .data.rel.ro.gopclntab lma 0x1666240 adjusted to 0x166636c
$ ./bad.exe version
runtime: pcHeader: magic= 0x0 pad1= 112 pad2= 211 minLC= 92 ptrSize= 1 pcHeader.textStart= 0x55b1423f3000 text= 0x55b1423f3000 pluginpath=
fatal error: invalid function symbol table
runtime: panic before malloc heap initialized
$ llvm-strip-16 -o good.exe gopls
$ ./good.exe version
[golang.org/x/tools/gopls](https://www.google.com/url?q=http://golang.org/x/tools/gopls&sa=D&source=buganizer&usg=AOvVaw11zqc7TmfhOipIIJbPeAWg) (devel)
$
The failure mode here ("invalid function symbol table") is due to the fact that the pclntab has been corrupted; when the Go runtime tries to read the pclntab section header it finds that the magic string is corrupted.
Unclear as to exactly what it is that is causing binutils strip
to do the wrong thing. Regardless, it would be great if we could come up with some sort of workaround (e.g. tweak our ELF generation in some way that will bypass the bug). Even if we track down the problem in strip (assuming it is indeed a bug there), Go users who run strip
are likely to run into this problem.
Also worth noting that this is not an issue with external linking; if we can figure out what it is that the external linker is doing to make strip
happy and do the same thing in the Go linker, that seems like it would be the best option.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status