1
0
mirror of https://github.com/golang/go synced 2024-11-14 23:00:29 -07:00

cmd/link/internal/ld: clean tmpdir obj timestamps

This patch changes the Go linker to "clean" (reset to Unix epoch) the
timestamps on object files copied to the tmpdir that is presented to
the external linker or archive tool. The intent is to improve build
reproducibility on Darwin, where later versions of xcode seem to want
to incorporate object file timestamps into the hash used for the final
build ID (which precludes the possibility of having reproducible Go
builds). Credit for this idea goes to Cherry (see
https://github.com/golang/go/issues/64947#issuecomment-1887667189).

Updates #64947.

Change-Id: I2eb7dddff538e247122b04fdcf8a57c923f61201
Reviewed-on: https://go-review.googlesource.com/c/go/+/585355
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Than McIntosh 2024-05-14 14:59:03 +00:00
parent c7c578cdf3
commit 3454ac0d63

View File

@ -47,6 +47,7 @@ import (
"sort"
"strings"
"sync"
"time"
"cmd/internal/bio"
"cmd/internal/goobj"
@ -1268,6 +1269,22 @@ func hostlinksetup(ctxt *Link) {
}
}
// cleanTimeStamps resets the timestamps for the specified list of
// existing files to the Unix epoch (1970-01-01 00:00:00 +0000 UTC).
// We take this step in order to help preserve reproducible builds;
// this seems to be primarily needed for external linking on on Darwin
// with later versions of xcode, which (unfortunately) seem to want to
// incorporate object file times into the final output file's build
// ID. See issue 64947 for the unpleasant details.
func cleanTimeStamps(files []string) {
epocht := time.Unix(0, 0)
for _, f := range files {
if err := os.Chtimes(f, epocht, epocht); err != nil {
Exitf("cannot chtimes %s: %v", f, err)
}
}
}
// hostobjCopy creates a copy of the object files in hostobj in a
// temporary directory.
func (ctxt *Link) hostobjCopy() (paths []string) {
@ -1360,9 +1377,14 @@ func (ctxt *Link) archive() {
if ctxt.HeadType == objabi.Haix {
argv = append(argv, "-X64")
}
godotopath := filepath.Join(*flagTmpdir, "go.o")
cleanTimeStamps([]string{godotopath})
hostObjCopyPaths := ctxt.hostobjCopy()
cleanTimeStamps(hostObjCopyPaths)
argv = append(argv, *flagOutfile)
argv = append(argv, filepath.Join(*flagTmpdir, "go.o"))
argv = append(argv, ctxt.hostobjCopy()...)
argv = append(argv, godotopath)
argv = append(argv, hostObjCopyPaths...)
if ctxt.Debugvlog != 0 {
ctxt.Logf("archive: %s\n", strings.Join(argv, " "))
@ -1733,8 +1755,13 @@ func (ctxt *Link) hostlink() {
argv = append(argv, compressDWARF)
}
argv = append(argv, filepath.Join(*flagTmpdir, "go.o"))
argv = append(argv, ctxt.hostobjCopy()...)
hostObjCopyPaths := ctxt.hostobjCopy()
cleanTimeStamps(hostObjCopyPaths)
godotopath := filepath.Join(*flagTmpdir, "go.o")
cleanTimeStamps([]string{godotopath})
argv = append(argv, godotopath)
argv = append(argv, hostObjCopyPaths...)
if ctxt.HeadType == objabi.Haix {
// We want to have C files after Go files to remove
// trampolines csects made by ld.