From 29b7c5c393fa0c5faf74f0b18c827a55d813725e Mon Sep 17 00:00:00 2001 From: Ed Schouten Date: Mon, 14 Aug 2023 11:16:29 +0200 Subject: [PATCH] cmd/link: add info.plist support via plist linker option This change adds a flag to the linker to allow it to embed info.plist data into the resulting binaries. This can, for example, be used to add code signing properties to binaries. --- src/cmd/link/internal/ld/data.go | 24 ++++++++++++++++++++++++ src/cmd/link/internal/ld/lib.go | 9 +++++++++ src/cmd/link/internal/ld/main.go | 4 ++++ 3 files changed, 37 insertions(+) diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index d651e2e346..1a3e4eb489 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -2360,6 +2360,30 @@ func appendString(data []byte, s string) []byte { return data } +// addPlist will add an info.Plist file, as segment __TEXT and section __info_plist. +// This is used when using the internal linker. Search in lib.go for __info_plist to find +// the external linker handling of this. Adding a section with an info.plist file allows +// Go executables to be code-signed for macOS. +func (ctxt *Link) addPlist(fn string) { + if fn == "" { + return + } + b, err := os.ReadFile(fn) + if err != nil { + Exitf("reading %s: %s", fn, err) + } + + ldr := ctxt.loader + sect := Segtext.Sections[len(Segtext.Sections)-1] + builder := ldr.MakeSymbolBuilder(".info.plist") // __info_list + builder.Addstring(string(b) + "\x00") // asciiz + builder.SetType(sym.SELFRXSECT) // Produces standalone section, without fixups + builder.SetAlign(16) // Sections don't seem to strictly require this + builder.SetReachable(true) // Don't let the linker drop it + builder.SetSect(sect) + ldr.SetSymSect(builder.Sym(), sect) +} + // assign addresses to text func (ctxt *Link) textaddress() { addsection(ctxt.loader, ctxt.Arch, &Segtext, ".text", 05) diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 91e2d5149c..66b3f1b500 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1811,6 +1811,15 @@ func (ctxt *Link) hostlink() { argv = append(argv, p) checkStatic(p) } + + // this will add an info.Plist file, as segment __TEXT and section __info_plist. + // This is used when using the external linker. Search in data.go for __info_plist to find + // the internal linker handling of this. Adding a section with an info.plist file allows + // Go executables to be code-signed for macOS. + if ctxt.LinkMode == LinkExternal && ctxt.IsDarwin() && *flagPlist != "" { + argv = append(argv, "-extldflags", fmt.Sprintf(`-sectcreate __TEXT __info_plist %q`, *flagPlist)) + } + if ctxt.HeadType == objabi.Hwindows { // Determine which linker we're using. Add in the extldflags in // case used has specified "-fuse-ld=...". diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 7743562909..eda4bfeb98 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -82,6 +82,8 @@ var ( flagCaptureHostObjs = flag.String("capturehostobjs", "", "capture host object files loaded during internal linking to specified dir") + flagPlist = flag.String("plist", "", "filename of info.plist to include") + flagA = flag.Bool("a", false, "no-op (deprecated)") FlagC = flag.Bool("c", false, "dump call graph") FlagD = flag.Bool("d", false, "disable dynamic executable") @@ -357,6 +359,8 @@ func Main(arch *sys.Arch, theArch Arch) { dwarfcompress(ctxt) bench.Start("layout") filesize := ctxt.layout(order) + bench.Start("plist") + ctxt.addPlist(*flagPlist) // Write out the output file. // It is split into two parts (Asmb and Asmb2). The first