go: cmd/link: add a flag to the linker to do not write function names to runtime.pclntab
What version of Go are you using (go version
)?
go version go version devel +71154e061f Tue Jan 14 17:13:34 2020 +0000 linux/amd64
Does this issue reproduce with the latest release?
Yes.
What operating system and processor architecture are you using (go env
)?
go env
Output
$ go env GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/home/experiment0/.cache/go-build" GOENV="/home/experiment0/.config/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GONOPROXY="" GONOSUMDB="" GOOS="linux" GOPATH="/home/experiment0/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/home/experiment0/.gimme/versions/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/home/experiment0/.gimme/versions/go/pkg/tool/linux_amd64" GCCGO="/usr/bin/gccgo" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build891839909=/tmp/go-build -gno-record-gcc-switches"
What did you do?
go get github.com/u-root/u-root
u-root -o /dev/null -build bb core boot
go get github.com/u-root/u-root/bb
go tool nm -size -sort size "$(go env GOPATH)"/bin/bb | head -1
What did you expect to see?
e02ba0 3836272 r runtime.pclntab
What did you see instead?
e39500 4808314 r runtime.pclntab
Proposal
I found here https://groups.google.com/d/msg/golang-nuts/hEdGYnqokZc/zQojaoWlAgAJ that a binary size could be reduced by avoiding of wasting space on function names within runtime.pclntab
. So I propose to add a linker flag (for example -stripfnnames
) to do that. We need such feature for applying Golang into embedded environments (with very limited total space).
I would like to prepare a PR if it will be approved.
About this issue
- Original URL
- State: open
- Created 4 years ago
- Reactions: 1
- Comments: 16 (7 by maintainers)
@xaionaro I’ve just implemented stripfnn flag:
Test results:
Sample panic outputs:
stripfn=1
stripfn=2
In case of stripfn=2 panics are almost unusable. But in case of stripfn=1 there is enough information to find the problem.
Clone https://github.com/embeddedgo/go and try it.
Would be nice to have stripfn flag in official Go too 🤔
I didn’t tested the
stripfn
flag much with go1.16.x but it seems with the last pcln changes it only strips the file names:stripfn=0
stripfn=1
stripfn=2
It seems the
stripfn=1
shrinks the binary enough to meet my current requirements therefore i didn’t investigated it further.Bellow are the numbers for the above code (linux/amd64):
See #36313
You can much easily introduce new things in a fork. Even Go teem itself creates
forksbranches for for a bigger changes.There is clearly no place for rarely used architectures or operating systems in the upstream but linux/thumb can be probably upstreamed as the 32-bit ARM seems to be now mainly used in embedded niche.
Simply send a pull request that implements -stripfnnames flag to the embeddedgo fork.
The embeddedgo compiler is released as patches to the original Go source so you can relatively easy see what was added/changed.
@xaionaro I think we can try to introduce such -stripfnnames flag to the embeddedgo fork. Can you help?
I’d love to test such flag because I’ve just reached the limit of 1 MiB Flash in STM32L476RG:
$ size shell.elf text data bss dec hex filename 1043876 3736 14004 1061616 1032f0 shell.elf
where pclntab is 345 KiB (34%):
$ nm --size-sort -S shell.elf|tail -5 08050104 00000fd4 T time.Time.AppendFormat 08059f98 00001444 T fmt.(*pp).printValue 200024e8 00001a74 B runtime.mheap_ 08040ce0 00003728 T unicode.init 080a89c0 000565ac r runtime.pclntab
The embeddedgo fork adds support for noos/thumb, noos/riscv64 and linux/thumb.
I use linux/thumb only to run tests but it is usable and you can give it a try (no cgo support, sorry). It generates compressed Thumb2 instructions instead of ARM instructions so it produces smaller binaries that can be run on almost any ARMv7-A machine.
The noos ones are for bare metal programming.
Ian may be concerned that you’ll eventually realize that Go isn’t the best choice for an embedded app, and switch to Rust or http://ziglang.org 😉
We can forbid using broken functions via the build-tag (added automatically by
-stripfnnames
).I believe the
testing.(*T).Helper
function, for example, will break.This will also likely break profiling information.
I understand that you would find it useful but I’m reluctant to endorse a change that will break code in ways that people will not know how to expect. I would rather find other ways to reduce binary size.
Removing function names from
runtime.pclntab
would break programs that useruntime.Callers
, which is a lot of programs. For example, thetesting
andlog
packages would partially break.