How to Leverage Go’s Symbol Table for Custom Variables and Smaller Binaries
Learn how Go’s embedded symbol table works, how to inspect and modify symbols using tools like nm and go tool nm, customize variables with ‑ldflags ‑X, and reduce binary size by stripping debug symbols, all illustrated with practical code examples.
Illustration created for “A Journey With Go”, made from the original Go Gopher, created by Renee French.
ℹ️ This article is based on Go 1.13.
The symbol table is generated and maintained by the compiler, storing information related to the program such as functions and global variables. Understanding the symbol table helps us interact with and leverage it.
Symbol Table
All binaries compiled by Go embed a symbol table by default. Below is an example and its analysis.
var AppVersion string
func main() {
fmt.Println(`Version: `+AppVersion)
}You can display the symbol table with the nm command; here is a partial result extracted from OSX:
0000000001177220 b io.ErrUnexpectedEOF
...
0000000001177250 b main.AppVersion
00000000010994c0 t main.main
...
0000000001170b00 d runtime.buildVersionThe b (bss) symbol marks uninitialized data. Since AppVersion is not initialized, it belongs to b. The d symbol indicates initialized data, and t denotes text symbols (functions).
Go also wraps the nm command; you can use go tool nm to achieve the same result:
1177220 B io.ErrUnexpectedEOF
...
1177250 B main.AppVersion
10994c0 T main.main
...
1170b00 D runtime.buildVersionOnce we know the exposed variable names, we can interact with them.
Custom Variables
When running go build, the process has two stages: compilation and linking. During linking, symbols from the symbol table are redirected into the final binary.
In Go we can rewrite a symbol definition using the -X flag, which takes two arguments: the name and the value. Example:
go build -o ex -ldflags="-X main.AppVersion=v1.0.0"Build and run the program; it now prints the version defined at build time:
Version: v1.0.0Running nm shows that the variable has been initialized:
1170a90 D main.AppVersionThe linker allows us to rewrite data symbols of type b or d as string. Below is a list of some symbols:
D runtime.badsystemstackMsg
D runtime.badmorestackgsignalMsg
D runtime.badmorestackg0Msg
B os.executablePath
B os.initCwd
B syscall.freebsdConfArch
D runtime/internal/sys.DefaultGoroot
B runtime.modinfo
B main.AppVersion
D runtime.buildVersionAmong them we see the previously defined variable and DefaultGoroot, both set automatically by the linker. Let’s look at the meaning of these runtime symbols.
Debugging
The symbol table exists to ensure identifiers are declared before use. After the program is built, the table is no longer needed, but by default it remains embedded in Go binaries to aid debugging.
Using gdb, you can load the binary with gdb ex and list the source:
GNU gdb (GDB) 8.3.1
...
Reading symbols from ex...
Loading Go Runtime support.
(gdb) list 10
6
7 var AppVersion string
8
9 func main() {
10 fmt.Println(`Version: `+AppVersion)
11 }
12
(gdb)GDB’s first step is to read the symbol table to extract function and symbol information. Using the -ldflags=-s flag removes the symbol table from the program. The new output shows no debugging symbols:
GNU gdb (GDB) 8.3.1
...
Reading symbols from ex...
(No debugging symbols found in ex)
(gdb) list
No symbol table is loaded. Use the "file" command.Note that removing the symbol table also strips the useful DWARF debugging information.
Binary Size
Removing the symbol table makes debugging harder but reduces binary size. Here is a size comparison:
2.0M ex
1.5M ex-sThe binary without the symbol table is about 25% smaller. Another example with the Go source code:
14M go
11M go-sBoth cases show a 25% reduction when symbols and DWARF information are omitted.
References
OSX: https://www.unix.com/man-page/osx/1/nm/
bss: https://en.wikipedia.org/wiki/.bss
Benjamin Poulain: https://twitter.com/awfulben
Unusual Speed Boost: Binary Size Matters: https://webkit.org/blog/2826/unusual-speed-boost-size-matters/
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
MaGe Linux Operations
Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
