cmd/internal/obj: add a flag to not write referenced symbol names in object file

The Go object file references (some of) symbols from other
packages by indices, not by names. The linker doesn't need the
symbol names to do the linking. The names are included in the
object file so it is self-contained and tools (objdump, nm) can
read the referenced symbol names. Including the names increases
object file size. Add a flag to disable it on demand (off by
default).

Change-Id: I143a0eb656997497c750b8eb1541341b2aee8f30
Reviewed-on: https://go-review.googlesource.com/c/go/+/404297
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Cherry Mui <cherryyz@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Cherry Mui 2022-05-05 17:22:17 -04:00
parent c1105cfd43
commit b89a194889
6 changed files with 39 additions and 6 deletions

View File

@ -31,6 +31,7 @@ type DebugFlags struct {
LocationLists int `help:"print information about DWARF location list creation"`
Nil int `help:"print information about nil checks"`
NoOpenDefer int `help:"disable open-coded defers"`
NoRefName int `help:"do not include referenced symbol names in object file"`
PCTab string `help:"print named pc-value table\nOne of: pctospadj, pctofile, pctoline, pctoinline, pctopcdata"`
Panic int `help:"show all compiler panics"`
Slice int `help:"print information about slice compilation"`

View File

@ -192,6 +192,7 @@ func ParseFlags() {
Ctxt.Flag_optimize = Flag.N == 0
Ctxt.Debugasm = int(Flag.S)
Ctxt.Flag_maymorestack = Debug.MayMoreStack
Ctxt.Flag_noRefName = Debug.NoRefName != 0
if flag.NArg() < 1 {
usage()

View File

@ -177,6 +177,7 @@ const (
PkgIdxHashed // Hashed (content-addressable) symbols
PkgIdxBuiltin // Predefined runtime symbols (ex: runtime.newobject)
PkgIdxSelf // Symbols defined in the current package
PkgIdxSpecial = PkgIdxSelf // Indices above it has special meanings
PkgIdxInvalid = 0
// The index of other referenced packages starts from 1.
)

View File

@ -899,6 +899,7 @@ type Link struct {
Flag_linkshared bool
Flag_optimize bool
Flag_locationlists bool
Flag_noRefName bool // do not include referenced symbol names in object file
Retpoline bool // emit use of retpoline stubs for indirect jmp/call
Flag_maymorestack string // If not "", call this function before stack checks
Bso *bufio.Writer

View File

@ -269,17 +269,21 @@ func (w *writer) StringTable() {
w.AddString(pkg)
}
w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
// TODO: this includes references of indexed symbols from other packages,
// for which the linker doesn't need the name. Consider moving them to
// a separate block (for tools only).
if w.pkgpath != "" {
s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
}
// Don't put names of builtins into the string table (to save
// space).
if s.PkgIdx == goobj.PkgIdxBuiltin {
return
}
// TODO: this includes references of indexed symbols from other packages,
// for which the linker doesn't need the name. Consider moving them to
// a separate block (for tools only).
if w.ctxt.Flag_noRefName && s.PkgIdx < goobj.PkgIdxSpecial {
// Don't include them if Flag_noRefName
return
}
if w.pkgpath != "" {
s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
}
w.AddString(s.Name)
})
@ -625,6 +629,9 @@ func (w *writer) refFlags() {
// Emits names of referenced indexed symbols, used by tools (objdump, nm)
// only.
func (w *writer) refNames() {
if w.ctxt.Flag_noRefName {
return
}
seen := make(map[*LSym]bool)
w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
switch rs.PkgIdx {

View File

@ -121,3 +121,25 @@ func TestSymbolTooLarge(t *testing.T) { // Issue 42054
t.Errorf("unexpected error message: want: %q, got: %s", want, out)
}
}
func TestNoRefName(t *testing.T) {
// Test that the norefname flag works.
testenv.MustHaveGoBuild(t)
tmpdir := t.TempDir()
src := filepath.Join(tmpdir, "x.go")
err := ioutil.WriteFile(src, []byte("package main; import \"fmt\"; func main() { fmt.Println(123) }\n"), 0666)
if err != nil {
t.Fatalf("failed to write source file: %v\n", err)
}
exe := filepath.Join(tmpdir, "x.exe")
// Build the fmt package with norefname. Not rebuilding all packages to save time.
// Also testing that norefname and non-norefname packages can link together.
cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags=fmt=-d=norefname", "-o", exe, src)
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("build failed: %v, output:\n%s", err, out)
}
}