Description
What version of Go are you using (go version
)?
go version go1.15.7 linux/amd64
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (go env
)?
go env
Output
go env GO111MODULE="" GOARCH="arm" GOBIN="" GOCACHE="/root/.cache/go-build" GOENV="/root/.config/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GOMODCACHE="/go/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="linux" GOPATH="/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/usr/local/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64" GCCGO="gccgo" GOARM="7" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="0" GOMOD="" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -marm -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build305676071=/tmp/go-build -gno-record-gcc-switches"
What did you do?
I have go
code that involves vectorizeable floating point instructions. When compiling for armv7l
, go
correctly uses vector floating-point instructions, but does not mark the resultant executable as a 'hard float' executable:
float_abi.go
source
package mainimport "fmt"
import "math/rand"func average(xs []float64) float64 {
total := 0.0
for _, v := range xs {
total += v
}
return total / float64(len(xs))
}func main() {
rand.Seed(0x6a756c6961)
xs := make([]float64, 1000)
for n := 0; n < 1000; n++ {
xs[n] = rand.Float64()
}
fmt.Println("average: ", average(xs))
}
Compiling:
$ docker run -ti -v $(pwd):/app -w /app -e GOARCH=arm -e GOARM=7 golang go build -o float_abi float_abi.go
Inspecting ELF headers:
$ readelf -h ./float_abi
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: ARM
Version: 0x1
Entry point address: 0x6e800
Start of program headers: 52 (bytes into file)
Start of section headers: 276 (bytes into file)
Flags: 0x5000002, Version5 EABI, <unknown>
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 7
Size of section headers: 40 (bytes)
Number of section headers: 25
Section header string table index: 3
Disassembly of average()
showcasing vector instructions:
$ arm-linux-gnueabihf-objdump -d ./float_abi | grep 'main.average>:' -A 18
0009daf8 <main.average>:
9daf8: e59d0008 ldr r0, [sp, #8]
9dafc: e59d1004 ldr r1, [sp, #4]
9db00: e3a02000 mov r2, #0
9db04: eeb70b00 vmov.f64 d0, #112 ; 0x3f800000 1.0
9db08: ee300b40 vsub.f64 d0, d0, d0
9db0c: ea000003 b 9db20 <main.average+0x28>
9db10: e0813182 add r3, r1, r2, lsl #3
9db14: ed931b00 vldr d1, [r3]
9db18: e2822001 add r2, r2, #1
9db1c: ee300b01 vadd.f64 d0, d0, d1
9db20: e1520000 cmp r2, r0
9db24: bafffff9 blt 9db10 <main.average+0x18>
9db28: ee0f0b10 vmov.32 d15[0], r0
9db2c: eeb81bcf vcvt.f64.s32 d1, s30
9db30: ee800b01 vdiv.f64 d0, d0, d1
9db34: ed8d0b04 vstr d0, [sp, #16]
9db38: e28ef000 add pc, lr, #0
Note the vadd.f64
and the use of dX
registers.
What did you expect to see?
I expect to see the Flags
field above to have 0x400
set, marking this executable as using the "hard float" ABI. See the definitions in glibc
which correspond to the values in the table on page 16 of this pdf.
What did you see instead?
Neither the hard nor soft float ABI flags are set, which I believe denotes that this program does not use any floating point arithmetic at all, which is clearly incorrect.