Skip to content

Commit e200ebf

Browse files
dmgkromaindoumenc
authored andcommitted
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 golang#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>
1 parent 3430014 commit e200ebf

File tree

3 files changed

+87
-6
lines changed

3 files changed

+87
-6
lines changed

src/cmd/link/elf_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,8 @@ func TestMergeNoteSections(t *testing.T) {
204204
expected := 1
205205

206206
switch runtime.GOOS {
207-
case "linux", "freebsd", "dragonfly":
208-
case "openbsd", "netbsd":
207+
case "linux", "dragonfly":
208+
case "openbsd", "netbsd", "freebsd":
209209
// These OSes require independent segment
210210
expected = 2
211211
default:

src/cmd/link/internal/ld/elf.go

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -607,8 +607,13 @@ func elfWriteMipsAbiFlags(ctxt *Link) int {
607607
return int(sh.Size)
608608
}
609609

610-
func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int) int {
611-
n := 3*4 + uint64(sz) + resoff%4
610+
func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sizes ...int) int {
611+
n := resoff % 4
612+
// if section contains multiple notes (as is the case with FreeBSD signature),
613+
// multiple note sizes can be specified
614+
for _, sz := range sizes {
615+
n += 3*4 + uint64(sz)
616+
}
612617

613618
sh.Type = uint32(elf.SHT_NOTE)
614619
sh.Flags = uint64(elf.SHF_ALLOC)
@@ -714,6 +719,67 @@ func elfwriteopenbsdsig(out *OutBuf) int {
714719
return int(sh.Size)
715720
}
716721

722+
// FreeBSD Signature (as per sys/elf_common.h)
723+
const (
724+
ELF_NOTE_FREEBSD_NAMESZ = 8
725+
ELF_NOTE_FREEBSD_DESCSZ = 4
726+
ELF_NOTE_FREEBSD_ABI_TAG = 1
727+
ELF_NOTE_FREEBSD_NOINIT_TAG = 2
728+
ELF_NOTE_FREEBSD_FEATURE_CTL_TAG = 4
729+
ELF_NOTE_FREEBSD_VERSION = 1203000 // 12.3-RELEASE
730+
ELF_NOTE_FREEBSD_FCTL_ASLR_DISABLE = 0x1
731+
)
732+
733+
const ELF_NOTE_FREEBSD_NAME = "FreeBSD\x00"
734+
735+
func elffreebsdsig(sh *ElfShdr, startva uint64, resoff uint64) int {
736+
n := ELF_NOTE_FREEBSD_NAMESZ + ELF_NOTE_FREEBSD_DESCSZ
737+
// FreeBSD signature section contains 3 equally sized notes
738+
return elfnote(sh, startva, resoff, n, n, n)
739+
}
740+
741+
// elfwritefreebsdsig writes FreeBSD .note section.
742+
//
743+
// See https://www.netbsd.org/docs/kernel/elf-notes.html for the description of
744+
// a Note element format and
745+
// https://github.com/freebsd/freebsd-src/blob/main/sys/sys/elf_common.h#L790
746+
// for the FreeBSD-specific values.
747+
func elfwritefreebsdsig(out *OutBuf) int {
748+
sh := elfshname(".note.tag")
749+
if sh == nil {
750+
return 0
751+
}
752+
out.SeekSet(int64(sh.Off))
753+
754+
// NT_FREEBSD_ABI_TAG
755+
out.Write32(ELF_NOTE_FREEBSD_NAMESZ)
756+
out.Write32(ELF_NOTE_FREEBSD_DESCSZ)
757+
out.Write32(ELF_NOTE_FREEBSD_ABI_TAG)
758+
out.WriteString(ELF_NOTE_FREEBSD_NAME)
759+
out.Write32(ELF_NOTE_FREEBSD_VERSION)
760+
761+
// NT_FREEBSD_NOINIT_TAG
762+
out.Write32(ELF_NOTE_FREEBSD_NAMESZ)
763+
out.Write32(ELF_NOTE_FREEBSD_DESCSZ)
764+
out.Write32(ELF_NOTE_FREEBSD_NOINIT_TAG)
765+
out.WriteString(ELF_NOTE_FREEBSD_NAME)
766+
out.Write32(0)
767+
768+
// NT_FREEBSD_FEATURE_CTL
769+
out.Write32(ELF_NOTE_FREEBSD_NAMESZ)
770+
out.Write32(ELF_NOTE_FREEBSD_DESCSZ)
771+
out.Write32(ELF_NOTE_FREEBSD_FEATURE_CTL_TAG)
772+
out.WriteString(ELF_NOTE_FREEBSD_NAME)
773+
if *flagRace {
774+
// The race detector can't handle ASLR, turn the ASLR off when compiling with -race.
775+
out.Write32(ELF_NOTE_FREEBSD_FCTL_ASLR_DISABLE)
776+
} else {
777+
out.Write32(0)
778+
}
779+
780+
return int(sh.Size)
781+
}
782+
717783
func addbuildinfo(val string) {
718784
if !strings.HasPrefix(val, "0x") {
719785
Exitf("-B argument must start with 0x: %s", val)
@@ -1327,6 +1393,9 @@ func (ctxt *Link) doelf() {
13271393
if ctxt.IsOpenbsd() {
13281394
shstrtab.Addstring(".note.openbsd.ident")
13291395
}
1396+
if ctxt.IsFreebsd() {
1397+
shstrtab.Addstring(".note.tag")
1398+
}
13301399
if len(buildinfo) > 0 {
13311400
shstrtab.Addstring(".note.gnu.build-id")
13321401
}
@@ -1820,7 +1889,7 @@ func asmbElf(ctxt *Link) {
18201889
phsh(ph, sh)
18211890
}
18221891

1823-
if ctxt.HeadType == objabi.Hnetbsd || ctxt.HeadType == objabi.Hopenbsd {
1892+
if ctxt.HeadType == objabi.Hnetbsd || ctxt.HeadType == objabi.Hopenbsd || ctxt.HeadType == objabi.Hfreebsd {
18241893
var sh *ElfShdr
18251894
switch ctxt.HeadType {
18261895
case objabi.Hnetbsd:
@@ -1830,8 +1899,12 @@ func asmbElf(ctxt *Link) {
18301899
case objabi.Hopenbsd:
18311900
sh = elfshname(".note.openbsd.ident")
18321901
resoff -= int64(elfopenbsdsig(sh, uint64(startva), uint64(resoff)))
1902+
1903+
case objabi.Hfreebsd:
1904+
sh = elfshname(".note.tag")
1905+
resoff -= int64(elffreebsdsig(sh, uint64(startva), uint64(resoff)))
18331906
}
1834-
// netbsd and openbsd require ident in an independent segment.
1907+
// NetBSD, OpenBSD and FreeBSD require ident in an independent segment.
18351908
pnotei := newElfPhdr()
18361909
pnotei.Type = elf.PT_NOTE
18371910
pnotei.Flags = elf.PF_R
@@ -2209,6 +2282,9 @@ elfobj:
22092282
if ctxt.HeadType == objabi.Hopenbsd {
22102283
a += int64(elfwriteopenbsdsig(ctxt.Out))
22112284
}
2285+
if ctxt.HeadType == objabi.Hfreebsd {
2286+
a += int64(elfwritefreebsdsig(ctxt.Out))
2287+
}
22122288
if len(buildinfo) > 0 {
22132289
a += int64(elfwritebuildinfo(ctxt.Out))
22142290
}

src/cmd/link/internal/ld/target.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ func (t *Target) IsOpenbsd() bool {
176176
return t.HeadType == objabi.Hopenbsd
177177
}
178178

179+
func (t *Target) IsFreebsd() bool {
180+
t.mustSetHeadType()
181+
return t.HeadType == objabi.Hfreebsd
182+
}
183+
179184
func (t *Target) mustSetHeadType() {
180185
if t.HeadType == objabi.Hunknown {
181186
panic("HeadType is not set")

0 commit comments

Comments
 (0)