return int(sh.Size)
}
-func addbuildinfo(val string) {
+func addbuildinfo(ctxt *Link) {
+ val := *flagHostBuildid
if val == "gobuildid" {
buildID := *flagBuildid
if buildID == "" {
Exitf("-B gobuildid requires a Go build ID supplied via -buildid")
}
+ if ctxt.IsDarwin() {
+ buildinfo = uuidFromGoBuildId(buildID)
+ return
+ }
+
hashedBuildID := hash.Sum32([]byte(buildID))
buildinfo = hashedBuildID[:20]
if !strings.HasPrefix(val, "0x") {
Exitf("-B argument must start with 0x: %s", val)
}
-
ov := val
val = val[2:]
- const maxLen = 32
+ maxLen := 32
+ if ctxt.IsDarwin() {
+ maxLen = 16
+ }
if hex.DecodedLen(len(val)) > maxLen {
Exitf("-B option too long (max %d digits): %s", maxLen, ov)
}
return &machohdr
}
+// Create a new Mach-O load command. ndata is the number of 32-bit words for
+// the data (not including the load command header).
func newMachoLoad(arch *sys.Arch, type_ uint32, ndata uint32) *MachoLoad {
if arch.PtrSize == 8 && (ndata&1 != 0) {
ndata++
}
}
+ if ctxt.IsInternal() && len(buildinfo) > 0 {
+ ml := newMachoLoad(ctxt.Arch, LC_UUID, 4)
+ // Mach-O UUID is 16 bytes
+ if len(buildinfo) < 16 {
+ buildinfo = append(buildinfo, make([]byte, 16)...)
+ }
+ // By default, buildinfo is already in UUIDv3 format
+ // (see uuidFromGoBuildId).
+ ml.data[0] = ctxt.Arch.ByteOrder.Uint32(buildinfo)
+ ml.data[1] = ctxt.Arch.ByteOrder.Uint32(buildinfo[4:])
+ ml.data[2] = ctxt.Arch.ByteOrder.Uint32(buildinfo[8:])
+ ml.data[3] = ctxt.Arch.ByteOrder.Uint32(buildinfo[12:])
+ }
+
if ctxt.IsInternal() && ctxt.NeedCodeSign() {
ml := newMachoLoad(ctxt.Arch, LC_CODE_SIGNATURE, 2)
ml.data[0] = uint32(codesigOff)
// to use this UUID flavor than any of the others. This is similar
// to how other linkers handle this (for example this code in lld:
// https://github.com/llvm/llvm-project/blob/2a3a79ce4c2149d7787d56f9841b66cacc9061d0/lld/MachO/Writer.cpp#L524).
- rv[6] &= 0xcf
+ rv[6] &= 0x0f
rv[6] |= 0x30
rv[8] &= 0x3f
rv[8] |= 0xc0
flagN = flag.Bool("n", false, "no-op (deprecated)")
FlagS = flag.Bool("s", false, "disable symbol table")
flag8 bool // use 64-bit addresses in symbol table
+ flagHostBuildid = flag.String("B", "", "set ELF NT_GNU_BUILD_ID `note` or Mach-O UUID; use \"gobuildid\" to generate it from the Go build ID")
flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker")
flagCheckLinkname = flag.Bool("checklinkname", true, "check linkname symbol references")
FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines")
flag.Var(&ctxt.LinkMode, "linkmode", "set link `mode`")
flag.Var(&ctxt.BuildMode, "buildmode", "set build `mode`")
flag.BoolVar(&ctxt.compressDWARF, "compressdwarf", true, "compress DWARF if possible")
- objabi.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF; use \"gobuildid\" to generate it from the Go build ID", addbuildinfo)
objabi.Flagfn1("L", "add specified `directory` to library path", func(a string) { Lflag(ctxt, a) })
objabi.AddVersionFlag() // -V
objabi.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) })
*flagBuildid = "go-openbsd"
}
+ if *flagHostBuildid != "" {
+ addbuildinfo(ctxt)
+ }
+
// enable benchmarking
var bench *benchmark.Metrics
if len(*benchmarkFlag) != 0 {
"bytes"
"log"
"os/exec"
+ "runtime"
"strings"
)
func main() {
- checkLinkOutput("", "-B argument must start with 0x")
+ // The cannot open file error indicates that the parsing of -B flag
+ // succeeded and it failed at a later step.
checkLinkOutput("0", "-B argument must start with 0x")
- checkLinkOutput("0x", "usage")
+ checkLinkOutput("0x", "cannot open file nonexistent.o")
checkLinkOutput("0x0", "-B argument must have even number of digits")
- checkLinkOutput("0x00", "usage")
+ checkLinkOutput("0x00", "cannot open file nonexistent.o")
checkLinkOutput("0xYZ", "-B argument contains invalid hex digit")
- checkLinkOutput("0x"+strings.Repeat("00", 32), "usage")
- checkLinkOutput("0x"+strings.Repeat("00", 33), "-B option too long (max 32 digits)")
+
+ maxLen := 32
+ if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
+ maxLen = 16
+ }
+ checkLinkOutput("0x"+strings.Repeat("00", maxLen), "cannot open file nonexistent.o")
+ checkLinkOutput("0x"+strings.Repeat("00", maxLen+1), "-B option too long")
}
func checkLinkOutput(buildid string, message string) {
- cmd := exec.Command("go", "tool", "link", "-B", buildid)
+ cmd := exec.Command("go", "tool", "link", "-B", buildid, "nonexistent.o")
out, err := cmd.CombinedOutput()
if err == nil {
log.Fatalf("expected cmd/link to fail")
}
if !strings.Contains(firstLine, message) {
- log.Fatalf("cmd/link output did not include expected message %q: %s", message, firstLine)
+ log.Fatalf("%s: cmd/link output did not include expected message %q: %s", buildid, message, firstLine)
}
}