Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

linux/sparc64 support for Go dependencies

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.

Use it

git clone https://github.com/shalseth/go-sparc64-deps
./go-sparc64-deps/mkfork.sh ~/sparc64-deps

That 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/

Other modules

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.

The termios control characters, and why input arrives in 4-byte lumps

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.

The stat layout, and why it needed fixing

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.

Versions

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

When some other package needs a file

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: SIGSTOP 17, SIGCHLD 20, SIGUSR1 30, SIGURG 16.
  • SIG_BLOCK 1, SIG_UNBLOCK 2, SIG_SETMASK 4.
  • O_CLOEXEC, EPOLL_CLOEXEC, EFD_CLOEXEC are 0x400000; EFD_NONBLOCK is 0x4000.
  • The kernel sigset_t is 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 mmap returns something like 0xfff8....
  • 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.

Related

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages