cmd/link: generate proper attributes for riscv profile
This CL adds `.riscv.attributes` to riscv64 link target
according to the profile setting which helps other
tools like gdb to identify vector/compress intrinsics
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index 6ff1d94..55ed539 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -19,6 +19,7 @@
"path/filepath"
"runtime"
"slices"
+ "sort"
"strings"
)
@@ -1442,6 +1443,9 @@
shstrtabAddstring(".MIPS.abiflags")
shstrtabAddstring(".gnu.attributes")
}
+ if ctxt.IsRISCV64() {
+ shstrtabAddstring(".riscv.attributes")
+ }
// generate .tbss section for dynamic internal linker or external
// linking, so that various binutils could correctly calculate
@@ -1500,6 +1504,9 @@
shstrtabAddstring(elfRelType + ".MIPS.abiflags")
shstrtabAddstring(elfRelType + ".gnu.attributes")
}
+ if ctxt.IsRISCV64() {
+ shstrtabAddstring(elfRelType + ".riscv.attributes")
+ }
// add a .note.GNU-stack section to mark the stack as non-executable
shstrtabAddstring(".note.GNU-stack")
@@ -1739,6 +1746,101 @@
gnuattributes.AddUint8(MIPS_FPABI_ANY)
}
}
+ if ctxt.IsRISCV64() {
+ attrs := ldr.CreateSymForUpdate(".riscv.attributes", 0)
+ attrs.SetType(sym.SELFROSECT)
+ attrs.SetReachable(true)
+ attrs.AddUint8('A') // version 'A'
+ secOff := attrs.AddUint32(ctxt.Arch, 0) // for sub-section length
+ attrs.Addstring("riscv") // sub-section vendor name
+ subOff := attrs.AddUint8(1) // Tag_file
+ subSize := attrs.AddUint32(ctxt.Arch, 0) // for sub-sub section size
+
+ attrs.AddUleb(4) // Tag_RISCV_stack_align
+ attrs.AddUleb(16) // default to profile 16 bytes alignment
+
+ attrs.AddUleb(5) // Tag_RISCV_arch
+ attrs.Addstring(genRISCVAttributes())
+
+ attrs.AddUleb(6) // Tag_RISCV_unaligned_access
+ attrs.AddUleb(1) // enable unaligned access
+
+ end := uint32(attrs.Size())
+ attrs.SetUint32(ctxt.Arch, subSize, end-uint32(subOff))
+ attrs.SetUint32(ctxt.Arch, secOff, end-uint32(secOff))
+ }
+}
+
+func genRISCVAttributes() string {
+ // According to RISC-V Instruction Set Manual Volume I, Chapter 39. ISA Extension Naming Conventions:
+ // ISA name strings are case-insensitive, but we use lower letter for alignment to gcc and clang
+ const (
+ extOrder = "imafdqlcbkjtpvh" + "zs" // the rest letters for sorting
+ errmsg = "invalid RISC-V ISA name: %s"
+ )
+ var extMap [256]int
+ for i, c := range extOrder {
+ extMap[c] = i + 1
+ }
+
+ extLess := func(a, b string, off int) bool {
+ ao := extMap[a[off]]
+ if ao == 0 {
+ Errorf(errmsg, a)
+ }
+
+ bo := extMap[b[off]]
+ if bo == 0 {
+ Errorf(errmsg, b)
+ }
+ return ao < bo
+ }
+
+ ns := []string{"i2", "m2", "a2", "f2", "d2", "c2", "zicclsm1"}
+ v := buildcfg.GORISCV64
+
+ if v == 20 {
+ ns = append(ns, "za128rs1")
+ }
+ if v >= 22 {
+ ns = append(ns, "b1", "zic64b1", "zihintpause1", "zba1", "zbb1",
+ "zbs1", "zicbom1", "zicbop1", "zicboz1", "zfhmin1", "zkt1")
+ }
+ if v >= 23 {
+ ns = append(ns, "v1", "zvfhmin1", "zvbb1", "zvkt1", "zihintntl1", "zicond1",
+ "zimop1", "zcmop1", "zcb1", "zfa1", "zawrs1")
+ }
+
+ sort.Slice(ns, func(i, j int) bool {
+ si, sj := ns[i], ns[j]
+ // The ABI spec require: ordered first by category, then alphabetically
+ // within a category.
+ if si[0] != sj[0] {
+ return extLess(si, sj, 0)
+ }
+
+ if si[1] != sj[1] { // Z* category
+ return extLess(si, sj, 1)
+ }
+
+ if len(si) < 4 {
+ Errorf(errmsg, si)
+ }
+
+ if len(sj) < 4 {
+ Errorf(errmsg, sj)
+ }
+
+ ml := min(len(si)-1, len(sj)-1) // compare without major version
+ for k := 2; k < ml; k++ {
+ if si[k] != sj[k] {
+ return si[k] < sj[k]
+ }
+ }
+ return si < sj // prefix are same
+ })
+
+ return fmt.Sprintf("rv64%s", strings.Join(ns, "_"))
}
// Do not write DT_NULL. elfdynhash will finish it.
@@ -2232,6 +2334,16 @@
shsym(sh, ldr, ldr.Lookup(".gnu.attributes", 0))
}
+ if ctxt.IsRISCV64() {
+ sh = elfshname(".riscv.attributes")
+ sh.Type = uint32(elf.SHT_RISCV_ATTRIBUTES)
+ sh.Flags = 0
+ sh.Addralign = 1
+
+ // RISC-V ABIs Specification deprecated PT_RISCV_ATTRIBUTES
+ shsym(sh, ctxt.loader, ctxt.loader.Lookup(".riscv.attributes", 0))
+ }
+
// put these sections early in the list
if !*FlagS {
elfshname(".symtab")
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Commit-Queue | +1 |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
Great! I am suprised that we didn't add this attribute before! Besides debugging, this attribute is useful when using objdump.
I don't know if we can test it in Golang source tree. We should be able to read this attribute via `readelf -A` and compare the output.
end := uint32(attrs.Size())And also add `ATOMIC_ABI`?
func genRISCVAttributes() string {The profile won't change after ratification, here I think we can just query a map from profile to arch string. :-)
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
I had a play with this. With the patch applied I was able to get binutils objdump to disassemble a Go program containing vector instructions.
ns := []string{"i2", "m2", "a2", "f2", "d2", "c2", "zicclsm1"}Should this be "i2p1", "a2p1","f2p2","d2p2" as we're working from version 20240411 of the ISA spec, or are we assuming outdated versions of these extensions?
v := buildcfg.GORISCV64We should also add zicsr2 as the runtime calls RDTIME.
if v >= 22 {Go binaries compiled with GORISCV64=RVA20U64 can still contain Vector and Zbb (used by OnesCount64) instructions. A runtime check is required before the instructions can be used but the instructions are still in the binary and may be executed. How should we handle this?
Perhaps we could always add 'v1' and 'zbb1' regardless of what profile is chosen and remember to update the base value of ns next time we use an new extension in this way, e.g,, when we add vector crypto support.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
if v >= 22 {Go binaries compiled with GORISCV64=RVA20U64 can still contain Vector and Zbb (used by OnesCount64) instructions. A runtime check is required before the instructions can be used but the instructions are still in the binary and may be executed. How should we handle this?
Perhaps we could always add 'v1' and 'zbb1' regardless of what profile is chosen and remember to update the base value of ns next time we use an new extension in this way, e.g,, when we add vector crypto support.
It is the same for ELFs with ifuncs when compiling C/C++. The ELF attribute contains only the baseline.
if v >= 22 {Pengcheng WangGo binaries compiled with GORISCV64=RVA20U64 can still contain Vector and Zbb (used by OnesCount64) instructions. A runtime check is required before the instructions can be used but the instructions are still in the binary and may be executed. How should we handle this?
Perhaps we could always add 'v1' and 'zbb1' regardless of what profile is chosen and remember to update the base value of ns next time we use an new extension in this way, e.g,, when we add vector crypto support.
It is the same for ELFs with ifuncs when compiling C/C++. The ELF attribute contains only the baseline.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Commit-Queue | +1 |
And also add `ATOMIC_ABI`?
Done
The profile won't change after ratification, here I think we can just query a map from profile to arch string. :-)
The problem is optional extensions, (i.e. `v` for rva22u64)
I think we easily can add vector into attribution after runtime do compiled vector instructions.
ns := []string{"i2", "m2", "a2", "f2", "d2", "c2", "zicclsm1"}Should this be "i2p1", "a2p1","f2p2","d2p2" as we're working from version 20240411 of the ISA spec, or are we assuming outdated versions of these extensions?
Done, Thanks
We should also add zicsr2 as the runtime calls RDTIME.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Commit-Queue | +1 |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Commit-Queue | +1 |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Commit-Queue | +1 |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
I'm confused by luci's settings that go1.25 using go1.22 to build. as gotip-riscv64 runs fine, I think it's OK to by pass. @jo...@sing.id.au @mark...@rivosinc.com
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| TryBot-Bypass | +1 |
According to https://github.com/golang/go/issues/76091, the tip code should not run with go1.25 , we can bypass the 1.25 failures.
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
// TODO(mzh): only gcc 14 supports atomic_abi and atomic_abi,duplicate?
ns := []string{"i2p1", "m2", "a2p1", "f2p2", "d2p2", "c2", "zicsr2", "zicclsm1"}```suggestion
ns := []string{"i2p1", "m2p0", "a2p1", "f2p2", "d2p2", "c2p0", "zicsr2p0", "zicclsm1"}
```
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Commit-Queue | +1 |
// TODO(mzh): only gcc 14 supports atomic_abi and atomic_abi,Meng Zhuoduplicate?
Done
ns := []string{"i2p1", "m2", "a2p1", "f2p2", "d2p2", "c2", "zicsr2", "zicclsm1"}```suggestion
ns := []string{"i2p1", "m2p0", "a2p1", "f2p2", "d2p2", "c2p0", "zicsr2p0", "zicclsm1"}
```
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |
| Commit-Queue | +1 |
| Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. |