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>
This commit is contained in:
Dmitri Goutnik 2022-06-15 14:50:19 -05:00
parent 005c78d8bb
commit c79b2009ef
3 changed files with 87 additions and 6 deletions

View File

@ -204,8 +204,8 @@ func TestMergeNoteSections(t *testing.T) {
expected := 1
switch runtime.GOOS {
case "linux", "freebsd", "dragonfly":
case "openbsd", "netbsd":
case "linux", "dragonfly":
case "openbsd", "netbsd", "freebsd":
// These OSes require independent segment
expected = 2
default:

View File

@ -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))
}

View File

@ -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")