Raspberry Pi上ARM架构的Golang程序出现SIGILL问题
Raspberry Pi上ARM架构的Golang程序出现SIGILL问题 我基本上在寻找一个开始排查错误的方向…
我正在为在Debian Linux下以32位模式运行的树莓派,从Windows交叉编译以下用于管理Azure存储的Azure应用程序:
为 go build 设置的环境变量如下:
$env:GOOS = "linux"
$env:GOARCH = "arm"
$env:GOARM= "5"
生成的程序通常可以在树莓派上执行,例如,我可以调用它来获取使用信息:
stm@raspberrypi:~$ ./azure-storage-azcopy -h
AzCopy 10.16.2
Project URL: github.com/Azure/azure-storage-azcopy
...
但是当我尝试实际执行操作时,它崩溃了:
stm@raspberrypi:~$ ./azure-storage-azcopy list https://some.blob.core.windows.net/videobackup
INFO: Authenticating to source using Azure AD
SIGILL: illegal instruction
PC=0x133ec m=5 sigcode=4
instruction bytes: 0x38 0x60 0x9f 0xe5 0x6 0x0 0x50 0xe1 0x6 0x0 0x0 0x9a 0x0 0x10 0xe0 0xe3
goroutine 1 [syscall]:
syscall.Syscall6(0x900137, 0x0, 0xfffffffd, 0x1, 0x0, 0x0, 0x0)
C:/Program Files/Go/src/syscall/syscall_linux.go:90 +0x8 fp=0x1a8f7a8 sp=0x1a8f770 pc=0xd7264
github.com/wastore/keyctl.keyctl(0x0, {0x1a8f818, 0x2, 0x2})
C:/Users/stm/go/pkg/mod/github.com/wastore/keyctl@v0.3.1/sys_linux.go:114 +0x158 fp=0x1a8f7f0 sp=0x1a8f7a8 pc=0x41e7a4
github.com/wastore/keyctl.newKeyring(0xfffffffd)
C:/Users/stm/go/pkg/mod/github.com/wastore/keyctl@v0.3.1/sys_linux.go:194 +0x4c fp=0x1a8f820 sp=0x1a8f7f0 pc=0x41ed4c
github.com/wastore/keyctl.SessionKeyring(...)
C:/Users/stm/go/pkg/mod/github.com/wastore/keyctl@v0.3.1/keyring.go:68
github.com/Azure/azure-storage-azcopy/v10/common.(*CredCache).hasCachedTokenInternal(0x151e3c0)
E:/Users/stm/Documents/GitHub/azure-storage-azcopy/common/credCache_linux.go:112 +0x1c fp=0x1a8f83c sp=0x1a8f820 pc=0x76f738
github.com/Azure/azure-storage-azcopy/v10/common.(*CredCache).HasCachedToken(0x151e3c0)
E:/Users/stm/Documents/GitHub/azure-storage-azcopy/common/credCache_linux.go:69 +0x34 fp=0x1a8f860 sp=0x1a8f83c pc=0x76f560
github.com/Azure/azure-storage-azcopy/v10/common.(*UserOAuthTokenManager).getCachedTokenInfo(0x17ffa70, {0xbb2770, 0x151f7a0})
E:/Users/stm/Documents/GitHub/azure-storage-azcopy/common/oauthTokenManager.go:513 +0x24 fp=0x1a8f9a4 sp=0x1a8f860 pc=0x783100
github.com/Azure/azure-storage-azcopy/v10/common.(*UserOAuthTokenManager).GetTokenInfo(0x17ffa70, {0xbb2770, 0x151f7a0})
E:/Users/stm/Documents/GitHub/azure-storage-azcopy/common/oauthTokenManager.go:129 +0xd4 fp=0x1a8fad0 sp=0x1a8f9a4 pc=0x780ee4
github.com/Azure/azure-storage-azcopy/v10/cmd.GetCredentialInfoForLocation({0xbb2770, 0x151f7a0}, 0x3, {0x152eb40, 0x2e}, {0x0, 0x0}, 0x1, {0x0, {0x0, ...}, ...})
... <long stackdump for multiple threads> ...
我想理解非法指令信号的原因:
SIGILL: illegal instruction
PC=0x133ec m=5 sigcode=4
instruction bytes: 0x38 0x60 0x9f 0xe5 0x6 0x0 0x50 0xe1 0x6 0x0 0x0 0x9a 0x0 0x10 0xe0 0xe3
当我用 arm-linux-gnueabihf-objdump -d azure-storage-azcopy 反汇编二进制文件时,我在有问题的地址 0x133ec 附近看到以下内容:
000133cc <runtime/internal/syscall.Syscall6>:
133cc: e59d7004 ldr r7, [sp, #4]
133d0: e59d0008 ldr r0, [sp, #8]
133d4: e59d100c ldr r1, [sp, #12]
133d8: e59d2010 ldr r2, [sp, #16]
133dc: e59d3014 ldr r3, [sp, #20]
133e0: e59d4018 ldr r4, [sp, #24]
133e4: e59d501c ldr r5, [sp, #28]
133e8: ef000000 svc 0x00000000
133ec: e59f6038 ldr r6, [pc, #56] ; 1342c <runtime/internal/syscall.Syscall6+0x60>
133f0: e1500006 cmp r0, r6
133f4: 9a000006 bls 13414 <runtime/internal/syscall.Syscall6+0x48>
我对ARM汇编不是很熟悉,但这看起来是有效的代码,并且字节序列 0x38 0x60 0x9f 0xe5 确实出现在汇编列表的地址 133ec: 处。
由于该项目本身为其他架构发布了此应用程序,并且显然在那里运行没有问题,我想知道我面对的是什么情况。这可能是编译错误,还是看起来像应用程序或库中的错误?
更多关于Raspberry Pi上ARM架构的Golang程序出现SIGILL问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Raspberry Pi上ARM架构的Golang程序出现SIGILL问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
从堆栈跟踪看,SIGILL发生在syscall.Syscall6执行后,具体在地址0x133ec的ldr r6, [pc, #56]指令处。虽然反汇编显示这是有效指令,但SIGILL通常由以下原因导致:
-
ARM架构版本不匹配:你的树莓派可能是ARMv6(如Raspberry Pi 1/Zero),但编译时可能使用了更高版本的指令集。
GOARM=5对应ARMv5,但某些依赖库可能包含ARMv6+的指令。 -
对齐问题:ARMv5要求内存访问对齐。
ldr指令在地址未对齐时可能触发SIGILL。 -
系统调用问题:
svc指令执行后,内核可能返回错误状态导致后续指令异常。
检查树莓派的具体架构:
cat /proc/cpuinfo | grep model
尝试使用GOARM=6或GOARM=7重新编译:
GOOS=linux GOARCH=arm GOARM=6 go build
如果问题依旧,检查依赖库github.com/wastore/keyctl是否包含ARM汇编代码。查看该库的sys_linux_arm.s文件:
// 检查是否有ARM特定实现
find . -name "*arm*.s" -type f
临时解决方案是禁用keyctl功能。在编译前修改credCache_linux.go:
// 注释掉keyctl相关调用
func (c *CredCache) hasCachedTokenInternal() bool {
return false // 临时绕过
}
或者使用CGO_ENABLED=0静态编译:
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=6 go build
检查二进制文件的ELF头确认架构:
readelf -h azure-storage-azcopy | grep Machine
如果显示"ARM"且Flags包含TLS(线程本地存储),可能需要检查内核配置。某些ARMv5设备不支持硬浮点,尝试使用软浮点:
GOARM=5 GOARCH=arm go build -tags=softfloat
实际示例:在Raspberry Pi 1(ARMv6)上编译时,正确设置GOARM=6:
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Printf("GOARM=%s\n", runtime.GOARM)
fmt.Printf("Architecture: %s/%s\n", runtime.GOOS, runtime.GOARCH)
}
编译命令:
GOOS=linux GOARCH=arm GOARM=6 go build -o testarm
在树莓派上运行验证架构信息。如果程序依赖特定ARM特性,可能需要更新内核或使用兼容性库。

