Arch files that golang.org/x/sys and golang.org/x/net are missing for
64-bit SPARC. Between them these two modules sit under most of the Go
ecosystem, so almost any non-trivial program needs them before it will build
for sparc64 — long before anything Alloy- or application-specific comes up.
Needs a toolchain that can target sparc64:
shalseth/go, branch sparc64.
git clone https://github.com/shalseth/go-sparc64-deps
./go-sparc64-deps/mkfork.sh ~/sparc64-depsThat clones x/sys and x/net at their pinned versions, checks them, and
applies the patches. Then in your own module:
replace golang.org/x/sys => /home/you/sparc64-deps/sys
replace golang.org/x/net => /home/you/sparc64-deps/net
GOOS=linux GOARCH=sparc64 CGO_ENABLED=0 go build ./...A directory replace needs no go.sum entry and works with GOPROXY=off, so
builds stay offline and reproducible. It also overrides transitive
dependencies — you do not need to care which of your dependencies pulled
x/sys in.
If you vendor, run go mod vendor first and copy the tree in instead:
cp -rf go-sparc64-deps/patches/. vendor/x/sys and x/net are what almost everything needs. A few other modules
carry per-architecture files of their own and are missing sparc64; these
come up as soon as you build real software. They are not cloned by
mkfork.sh — copy the files into your vendor/ tree, or into the module
cache, the same way:
cp -rf go-sparc64-deps/patches/. vendor/| module | what is missing | why |
|---|---|---|
github.com/moby/sys/signal |
signal_linux_sparc64.go |
The package assumes every non-MIPS Linux architecture has SIGSTKFLT. SPARC keeps the SunOS numbering: signal 16 is SIGURG and signal 7 is SIGEMT, so unix.SIGSTKFLT does not exist. Mirrors the MIPS variant upstream already ships. SIGRTMAX is 64, as in the generic file, so only the one map entry differs. |
go.etcd.io/bbolt |
internal/common/bolt_sparc64.go |
Every architecture gets a file defining MaxMapSize and MaxAllocSize; sparc64 had none. Same values as the other 64-bit targets. |
moby/sys/signal also needs its generic file to stop claiming sparc64, which
is a change to a tracked file rather than a new one, so it lives in
diffs/moby-sys-signal-exclude-sparc64.patch.
Both were found building app-containers/containerd, which needs one more
thing that is not a dependency problem: its Makefile.linux adds
-buildmode=pie for every architecture except a handful, and this port has
no position-independent code model, so sparc64 belongs in that filter next
to mips and ppc64.
zerrors_linux_sparc64.go carried the generic Linux values for three termios
control-character indices. SPARC numbers them differently, because its NCCS
is small enough that the canonical and non-canonical slots share storage:
| kernel | x/sys shipped | |
|---|---|---|
VMIN |
4 (shares the slot with VEOF) |
6 |
VEOL |
5 (shares the slot with VTIME) |
11 |
VEOL2 |
6 | 16 |
VMIN is the damaging one. Putting a terminal into raw mode means
termios.Cc[unix.VMIN] = 1, which every terminal library does - moby/term,
containerd/console, golang.org/x/term. With the wrong index that writes to
a slot nothing reads, SPARC's real VMIN keeps its default of 4, and every
read on the terminal blocks until four bytes arrive.
The visible effect is an interactive session that looks broken rather than
slow: docker run -it delivers stdin in 4-byte groups, so you type four
characters before any of them appear, and a single Return does nothing until
something else follows it.
Verified against the kernel's own termbits.h on an UltraSPARC T4-1, and by
watching a container receive keystrokes through a bind mount: nothing for
three keys, then four bytes at once. Fixed, docker run -it echoes one byte
per keystroke like any other architecture.
sparc64 has two stat structs, and upstream x/sys mixed them. The newstat
family — stat(38), lstat(40), fstat(62) — fills a 104-byte
struct stat with a 32-bit st_dev, a short st_nlink and timestamps
carrying no nanoseconds. The 64 family — stat64(139), fstat64(63),
fstatat64(289) — fills a 144-byte struct stat64 with 64-bit fields
throughout and three timespecs.
Upstream declares Stat, Lstat and Fstat as the newstat calls but
Fstatat as fstatat64, so four functions filled one Stat_t from two
incompatible layouts — and Stat_t matched neither: a uint16 pad after
Dev and Nlink as uint32 put Ino, Nlink and Size at the wrong
offsets, while Mode and Rdev landed correctly by coincidence. Nothing
could have caught it, because until the syscall trampolines existed the
package did not build here at all.
The files here settle on struct stat64, the way the architectures with no
legacy stat calls already do: Stat and Lstat are wrappers over
Fstatat, Fstat uses SYS_FSTAT64, and Stat_t has the layout the
kernel actually writes. Flock_t also gains the four bytes of padding that
8-align Start.
Checked on an UltraSPARC T4-1 against the kernel's own asm/stat.h and a
raw syscall dump, then field by field against stat(1) — dev, ino, nlink,
mode, uid, gid, size, blksize, blocks, and Rdev major/minor on
/dev/null. Stat, Lstat, Fstat and Fstatat agree with each other.
Two more strict-alignment fixes ride along, both found by x/sys's own test
suite once it could run: ReadDirent now hands getdents64 an aligned
buffer, because SPARC faults on the unaligned 64-bit d_ino store and the
kernel returns EFAULT for it; and the Ifreq union accessors go through
encoding/binary instead of casting a pointer into a byte array whose
struct has an alignment of one.
With all of it, go test ./unix/ on real hardware is 153 passing and one
failure, TestSockaddrALG, which wants a kernel built with
CONFIG_CRYPTO_USER_API_HASH.
Pinned to x/sys v0.47.0 and x/net v0.57.0. Override with SYS_VER and
NET_VER. Nine files are new and normally carry forward across version bumps
untouched; nine are upstream files that are overwritten — three x/net
build-tag edits and six x/sys files the generator already emits for
sparc64 — and those are checksum-verified first, so a bump that moves them
stops the script rather than silently reverting an upstream change.
| package | files | what |
|---|---|---|
x/sys/unix |
8 | syscall numbers, errno and signal tables, types, asm_linux_sparc64.s, Ifreq alignment, getdents buffer alignment |
x/sys/cpu |
1 | cacheLineSize and initOptions |
x/net/internal/socket |
5 | recvmmsg 328, sendmmsg 336; msghdr/cmsghdr/iovec layouts |
x/net/ipv4, x/net/ipv6 |
2 | sockopt struct layouts |
moby/sys/signal |
1 | SPARC has no SIGSTKFLT |
bbolt |
1 | maxMapSize / maxAllocSize |
Sooner or later a dependency fails to build because it has a
foo_linux_amd64.go and nothing for sparc64. Two shapes come up:
A missing arch file. Copy the closest existing 64-bit big-endian variant —
ppc64 or s390x, never amd64 — and correct the constants. Watch for:
- SunOS signal numbers:
SIGSTOP17,SIGCHLD20,SIGUSR130,SIGURG16. SIG_BLOCK1,SIG_UNBLOCK2,SIG_SETMASK4.O_CLOEXEC,EPOLL_CLOEXEC,EFD_CLOEXECare0x400000;EFD_NONBLOCKis0x4000.- The kernel
sigset_tis one 64-bit word, not[2]uint32— on a big-endian machine the split form puts signals 1-32 in the wrong half. - Userspace addresses are 52-bit and sign-extended, so an unhinted
mmapreturns something like0xfff8.... - Structs are big-endian throughout, and padding often differs from amd64 even when field order matches.
A build tag that omits sparc64. Files named *_64bit.go or similar often
list architectures explicitly. Add sparc64 to the list — and if you do this
in x/sys or x/net, send it here so the next person gets it too.
Generated files (zerrors_, zsysnum_, ztypes_) can be regenerated on a
real sparc64 box with the mkall.sh / mkerrors.sh scripts in
x/sys/unix, which read the installed kernel headers.
- shalseth/go — the toolchain port
- shalseth/alloy-sparc64 — Grafana Alloy, using this repo