aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/link/internal
diff options
context:
space:
mode:
authorDmitri Goutnik <dgoutnik@gmail.com>2022-06-15 14:50:19 -0500
committerDmitri Goutnik <dgoutnik@gmail.com>2022-10-13 21:14:48 +0000
commitc79b2009ef0b82e9c50ced139b2fd752018da0dd (patch)
treef72cc3dcafc0e7cbea705cf8490d1ea79a8c5e83 /src/cmd/link/internal
parent005c78d8bbf6389d482a0bbb4e6c46719d77f59f (diff)
downloadgo-c79b2009ef0b82e9c50ced139b2fd752018da0dd.tar.xz
cmd/link: define ELF .note section on FreeBSD
Write .note signature section when targeting FreeBSD, similar to NetBSD and OpenBSD. This allows binaries to declare the ABI version they were compiled for and opt out of ASLR when compiled with -race. Fixes #48164 Change-Id: Ie54dd5c70697a3f42a75fd640540350fd8a4dc71 Reviewed-on: https://go-review.googlesource.com/c/go/+/412494 Reviewed-by: Meng Zhuo <mzh@golangcn.org> Reviewed-by: Cherry Mui <cherryyz@google.com> Reviewed-by: Than McIntosh <thanm@google.com> Reviewed-by: Yuval Pavel Zholkover <paulzhol@gmail.com>
Diffstat (limited to 'src/cmd/link/internal')
-rw-r--r--src/cmd/link/internal/ld/elf.go84
-rw-r--r--src/cmd/link/internal/ld/target.go5
2 files changed, 85 insertions, 4 deletions
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index dd5844bd10..41fc9ab76f 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -607,8 +607,13 @@ func elfWriteMipsAbiFlags(ctxt *Link) int {
return int(sh.Size)
}
-func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int) int {
- n := 3*4 + uint64(sz) + resoff%4
+func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sizes ...int) int {
+ n := resoff % 4
+ // if section contains multiple notes (as is the case with FreeBSD signature),
+ // multiple note sizes can be specified
+ for _, sz := range sizes {
+ n += 3*4 + uint64(sz)
+ }
sh.Type = uint32(elf.SHT_NOTE)
sh.Flags = uint64(elf.SHF_ALLOC)
@@ -714,6 +719,67 @@ func elfwriteopenbsdsig(out *OutBuf) int {
return int(sh.Size)
}
+// FreeBSD Signature (as per sys/elf_common.h)
+const (
+ ELF_NOTE_FREEBSD_NAMESZ = 8
+ ELF_NOTE_FREEBSD_DESCSZ = 4
+ ELF_NOTE_FREEBSD_ABI_TAG = 1
+ ELF_NOTE_FREEBSD_NOINIT_TAG = 2
+ ELF_NOTE_FREEBSD_FEATURE_CTL_TAG = 4
+ ELF_NOTE_FREEBSD_VERSION = 1203000 // 12.3-RELEASE
+ ELF_NOTE_FREEBSD_FCTL_ASLR_DISABLE = 0x1
+)
+
+const ELF_NOTE_FREEBSD_NAME = "FreeBSD\x00"
+
+func elffreebsdsig(sh *ElfShdr, startva uint64, resoff uint64) int {
+ n := ELF_NOTE_FREEBSD_NAMESZ + ELF_NOTE_FREEBSD_DESCSZ
+ // FreeBSD signature section contains 3 equally sized notes
+ return elfnote(sh, startva, resoff, n, n, n)
+}
+
+// elfwritefreebsdsig writes FreeBSD .note section.
+//
+// See https://www.netbsd.org/docs/kernel/elf-notes.html for the description of
+// a Note element format and
+// https://github.com/freebsd/freebsd-src/blob/main/sys/sys/elf_common.h#L790
+// for the FreeBSD-specific values.
+func elfwritefreebsdsig(out *OutBuf) int {
+ sh := elfshname(".note.tag")
+ if sh == nil {
+ return 0
+ }
+ out.SeekSet(int64(sh.Off))
+
+ // NT_FREEBSD_ABI_TAG
+ out.Write32(ELF_NOTE_FREEBSD_NAMESZ)
+ out.Write32(ELF_NOTE_FREEBSD_DESCSZ)
+ out.Write32(ELF_NOTE_FREEBSD_ABI_TAG)
+ out.WriteString(ELF_NOTE_FREEBSD_NAME)
+ out.Write32(ELF_NOTE_FREEBSD_VERSION)
+
+ // NT_FREEBSD_NOINIT_TAG
+ out.Write32(ELF_NOTE_FREEBSD_NAMESZ)
+ out.Write32(ELF_NOTE_FREEBSD_DESCSZ)
+ out.Write32(ELF_NOTE_FREEBSD_NOINIT_TAG)
+ out.WriteString(ELF_NOTE_FREEBSD_NAME)
+ out.Write32(0)
+
+ // NT_FREEBSD_FEATURE_CTL
+ out.Write32(ELF_NOTE_FREEBSD_NAMESZ)
+ out.Write32(ELF_NOTE_FREEBSD_DESCSZ)
+ out.Write32(ELF_NOTE_FREEBSD_FEATURE_CTL_TAG)
+ out.WriteString(ELF_NOTE_FREEBSD_NAME)
+ if *flagRace {
+ // The race detector can't handle ASLR, turn the ASLR off when compiling with -race.
+ out.Write32(ELF_NOTE_FREEBSD_FCTL_ASLR_DISABLE)
+ } else {
+ out.Write32(0)
+ }
+
+ return int(sh.Size)
+}
+
func addbuildinfo(val string) {
if !strings.HasPrefix(val, "0x") {
Exitf("-B argument must start with 0x: %s", val)
@@ -1327,6 +1393,9 @@ func (ctxt *Link) doelf() {
if ctxt.IsOpenbsd() {
shstrtab.Addstring(".note.openbsd.ident")
}
+ if ctxt.IsFreebsd() {
+ shstrtab.Addstring(".note.tag")
+ }
if len(buildinfo) > 0 {
shstrtab.Addstring(".note.gnu.build-id")
}
@@ -1820,7 +1889,7 @@ func asmbElf(ctxt *Link) {
phsh(ph, sh)
}
- if ctxt.HeadType == objabi.Hnetbsd || ctxt.HeadType == objabi.Hopenbsd {
+ if ctxt.HeadType == objabi.Hnetbsd || ctxt.HeadType == objabi.Hopenbsd || ctxt.HeadType == objabi.Hfreebsd {
var sh *ElfShdr
switch ctxt.HeadType {
case objabi.Hnetbsd:
@@ -1830,8 +1899,12 @@ func asmbElf(ctxt *Link) {
case objabi.Hopenbsd:
sh = elfshname(".note.openbsd.ident")
resoff -= int64(elfopenbsdsig(sh, uint64(startva), uint64(resoff)))
+
+ case objabi.Hfreebsd:
+ sh = elfshname(".note.tag")
+ resoff -= int64(elffreebsdsig(sh, uint64(startva), uint64(resoff)))
}
- // netbsd and openbsd require ident in an independent segment.
+ // NetBSD, OpenBSD and FreeBSD require ident in an independent segment.
pnotei := newElfPhdr()
pnotei.Type = elf.PT_NOTE
pnotei.Flags = elf.PF_R
@@ -2209,6 +2282,9 @@ elfobj:
if ctxt.HeadType == objabi.Hopenbsd {
a += int64(elfwriteopenbsdsig(ctxt.Out))
}
+ if ctxt.HeadType == objabi.Hfreebsd {
+ a += int64(elfwritefreebsdsig(ctxt.Out))
+ }
if len(buildinfo) > 0 {
a += int64(elfwritebuildinfo(ctxt.Out))
}
diff --git a/src/cmd/link/internal/ld/target.go b/src/cmd/link/internal/ld/target.go
index cc8e4181b6..d0ce99f3e9 100644
--- a/src/cmd/link/internal/ld/target.go
+++ b/src/cmd/link/internal/ld/target.go
@@ -176,6 +176,11 @@ func (t *Target) IsOpenbsd() bool {
return t.HeadType == objabi.Hopenbsd
}
+func (t *Target) IsFreebsd() bool {
+ t.mustSetHeadType()
+ return t.HeadType == objabi.Hfreebsd
+}
+
func (t *Target) mustSetHeadType() {
if t.HeadType == objabi.Hunknown {
panic("HeadType is not set")