mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/link: apply -B UUID to external linking on Mach-O
Currently, on Mach-O, the -B UUID setting is only applied in internal linking mode, whereas in external linking mode the UUID is always rewritten to a hash of Go build ID. This CL makes it apply to external linking as well. This makes the behavior consistent on both linkmodes, and also consistent with the -B flag's behavior for GNU build ID on ELF. Add tests. Updates #68678. Cq-Include-Trybots: luci.golang.try:gotip-darwin-amd64_14,gotip-darwin-arm64_13 Change-Id: I276a5930e231141440cdba16e8812df28ac4237b Reviewed-on: https://go-review.googlesource.com/c/go/+/618599 Reviewed-by: Than McIntosh <thanm@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
This commit is contained in:
parent
6a4feb5644
commit
c15e589733
4 changed files with 83 additions and 6 deletions
|
|
@ -1468,6 +1468,9 @@ func (ctxt *Link) hostlink() {
|
|||
argv = append(argv, "-Wl,-x")
|
||||
}
|
||||
}
|
||||
if *flagHostBuildid == "none" {
|
||||
argv = append(argv, "-Wl,-no_uuid")
|
||||
}
|
||||
case objabi.Hopenbsd:
|
||||
argv = append(argv, "-pthread")
|
||||
if ctxt.BuildMode != BuildModePIE {
|
||||
|
|
@ -2059,7 +2062,7 @@ func (ctxt *Link) hostlink() {
|
|||
uuidUpdated = true
|
||||
}
|
||||
}
|
||||
if ctxt.IsDarwin() && !uuidUpdated && *flagBuildid != "" {
|
||||
if ctxt.IsDarwin() && !uuidUpdated && len(buildinfo) > 0 {
|
||||
updateMachoOutFile("rewriting uuid",
|
||||
func(ctxt *Link, exef *os.File, exem *macho.File, outexe string) error {
|
||||
return machoRewriteUuid(ctxt, exef, exem, outexe)
|
||||
|
|
|
|||
|
|
@ -195,8 +195,9 @@ func machoCombineDwarf(ctxt *Link, exef *os.File, exem *macho.File, dsym, outexe
|
|||
case imacho.LC_UUID:
|
||||
var u uuidCmd
|
||||
err = reader.ReadAt(0, &u)
|
||||
if err == nil {
|
||||
copy(u.Uuid[:], uuidFromGoBuildId(*flagBuildid))
|
||||
if err == nil && len(buildinfo) > 0 {
|
||||
clear(u.Uuid[:])
|
||||
copy(u.Uuid[:], buildinfo)
|
||||
err = reader.WriteAt(0, &u)
|
||||
}
|
||||
case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread,
|
||||
|
|
|
|||
|
|
@ -86,7 +86,8 @@ func machoRewriteUuid(ctxt *Link, exef *os.File, exem *macho.File, outexe string
|
|||
if err := reader.ReadAt(0, &u); err != nil {
|
||||
return err
|
||||
}
|
||||
copy(u.Uuid[:], uuidFromGoBuildId(*flagBuildid))
|
||||
clear(u.Uuid[:])
|
||||
copy(u.Uuid[:], buildinfo)
|
||||
if err := reader.WriteAt(0, &u); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
imacho "cmd/internal/macho"
|
||||
"cmd/internal/sys"
|
||||
)
|
||||
|
||||
|
|
@ -386,7 +387,6 @@ func TestMachOBuildVersion(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
found := false
|
||||
const LC_BUILD_VERSION = 0x32
|
||||
checkMin := func(ver uint32) {
|
||||
major, minor, patch := (ver>>16)&0xff, (ver>>8)&0xff, (ver>>0)&0xff
|
||||
if major < 11 {
|
||||
|
|
@ -396,7 +396,7 @@ func TestMachOBuildVersion(t *testing.T) {
|
|||
for _, cmd := range exem.Loads {
|
||||
raw := cmd.Raw()
|
||||
type_ := exem.ByteOrder.Uint32(raw)
|
||||
if type_ != LC_BUILD_VERSION {
|
||||
if type_ != imacho.LC_BUILD_VERSION {
|
||||
continue
|
||||
}
|
||||
osVer := exem.ByteOrder.Uint32(raw[12:])
|
||||
|
|
@ -411,6 +411,78 @@ func TestMachOBuildVersion(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMachOUUID(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
if runtime.GOOS != "darwin" {
|
||||
t.Skip("this is only for darwin")
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
|
||||
tmpdir := t.TempDir()
|
||||
|
||||
src := filepath.Join(tmpdir, "main.go")
|
||||
err := os.WriteFile(src, []byte(trivialSrc), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
extractUUID := func(exe string) string {
|
||||
exem, err := macho.Open(exe)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer exem.Close()
|
||||
for _, cmd := range exem.Loads {
|
||||
raw := cmd.Raw()
|
||||
type_ := exem.ByteOrder.Uint32(raw)
|
||||
if type_ != imacho.LC_UUID {
|
||||
continue
|
||||
}
|
||||
return string(raw[8:24])
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
tests := []struct{ name, ldflags, expect string }{
|
||||
{"default", "", "gobuildid"},
|
||||
{"gobuildid", "-B=gobuildid", "gobuildid"},
|
||||
{"specific", "-B=0x0123456789ABCDEF0123456789ABCDEF", "\x01\x23\x45\x67\x89\xAB\xCD\xEF\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
|
||||
{"none", "-B=none", ""},
|
||||
}
|
||||
if testenv.HasCGO() {
|
||||
for _, test := range tests {
|
||||
t1 := test
|
||||
t1.name += "_external"
|
||||
t1.ldflags += " -linkmode=external"
|
||||
tests = append(tests, t1)
|
||||
}
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
exe := filepath.Join(tmpdir, test.name)
|
||||
cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags="+test.ldflags, "-o", exe, src)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
|
||||
}
|
||||
uuid := extractUUID(exe)
|
||||
if test.expect == "gobuildid" {
|
||||
// Go buildid is not known in source code. Check UUID is present,
|
||||
// and satisifies UUIDv3.
|
||||
if uuid == "" {
|
||||
t.Fatal("expect nonempty UUID, got empty")
|
||||
}
|
||||
// The version number is the high 4 bits of byte 6.
|
||||
if uuid[6]>>4 != 3 {
|
||||
t.Errorf("expect v3 UUID, got %X (version %d)", uuid, uuid[6]>>4)
|
||||
}
|
||||
} else if uuid != test.expect {
|
||||
t.Errorf("UUID mismatch: got %X, want %X", uuid, test.expect)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const Issue34788src = `
|
||||
|
||||
package blah
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue