Raspberry Pi上ARM架构的Golang程序出现SIGILL问题

Raspberry Pi上ARM架构的Golang程序出现SIGILL问题 我基本上在寻找一个开始排查错误的方向…

我正在为在Debian Linux下以32位模式运行的树莓派,从Windows交叉编译以下用于管理Azure存储的Azure应用程序:

GitHub - Azure/azure-storage-azcopy: The new Azure Storage data transfer...

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

1 回复

更多关于Raspberry Pi上ARM架构的Golang程序出现SIGILL问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


从堆栈跟踪看,SIGILL发生在syscall.Syscall6执行后,具体在地址0x133ecldr r6, [pc, #56]指令处。虽然反汇编显示这是有效指令,但SIGILL通常由以下原因导致:

  1. ARM架构版本不匹配:你的树莓派可能是ARMv6(如Raspberry Pi 1/Zero),但编译时可能使用了更高版本的指令集。GOARM=5对应ARMv5,但某些依赖库可能包含ARMv6+的指令。

  2. 对齐问题:ARMv5要求内存访问对齐。ldr指令在地址未对齐时可能触发SIGILL。

  3. 系统调用问题svc指令执行后,内核可能返回错误状态导致后续指令异常。

检查树莓派的具体架构:

cat /proc/cpuinfo | grep model

尝试使用GOARM=6GOARM=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特性,可能需要更新内核或使用兼容性库。

回到顶部