Eight Characters: Porting Berkeley SoftFloat to MVS 3.8j
A 1981 mainframe gives an external symbol eight uppercase characters. Berkeley SoftFloat names its functions things like softfloat_roundPackToF64. ONFLY needs both, and reconciling them took three separate measured failures on real hardware emulation.
Why a fly-brain simulation carries its own floating point
ONFLY runs a fruit fly feeding circuit as a mainframe workload, and requires that identical requests produce identical fingerprints on every platform it targets. Hardware arithmetic cannot deliver that across S/370 hexadecimal floating point and IEEE binary, so the engine implements IEEE 754 in software.
Upstream states the constraint that decides which release you get. Since Release 3, SoftFloat depends on a 64-bit integer type in C, and a compiler without one is directed to the older Release 2c for the 32-bit and 64-bit formats (Berkeley SoftFloat).
GCCMVS is that compiler. Release 3e failed on it for four independent reasons: internal compiler errors at four distinct points, a silently wrong variable 64-bit left shift, no 64-bit runtime helpers in PDPCLIB, and a code generation bug asking for them the wrong way. Release 2c's bits32 build carries a float64 as two 32-bit halves and forms no 64-bit integer anywhere.
Three include names that all resolve to one PDS member
GCCMVS resolves #include "name" to the partitioned dataset member given by the first eight characters of the name, uppercased, with punctuation and extension included. Measured on TK5 on 2026-09-11 against a single member SOFTFLOA: the spellings "softfloat.h", "softfloat-macros", "softfloat-specialize" and "softfloa.h" all resolved to it, return code 0.
Release 2c's bits32/softfloat.c includes three of those names, and three files cannot occupy one member. Concatenating libraries on the DD statement does not help, because MVS takes a member from the first library that has it. Renaming the files was off the table, since the vendored tree stays byte-identical to its recorded SHA-256 digests.
GCC's -remap option exists for filesystems with very short names, which is precisely this situation. On this port it is accepted and inert. The build amalgamates instead: the includes are inlined in order at submit time and never written to disk, so no second copy of the source exists to drift from the first.
What Assembler XF said about 38 of 42 external names
With the includes resolved, Release 2c compiled at return code 0 and the assembler rejected the output:
IFO196 FLOAT64@ HAS BEEN PREVIOUSLY DEFINED
IFO196 FLOAT32@ HAS BEEN PREVIOUSLY DEFINED
IFO196 INT32@TO HAS BEEN PREVIOUSLY DEFINED
IFO189 INVALID ENTRY OPERAND, LINKAGE CANNOT BE PERFORMED
Truncated to eight characters, 38 of Release 2c's 42 externals fall into three colliding groups: eighteen float32_*, eighteen float64_* and two int32_to_*. Splitting the library across translation units only moves the collision from the assembler to the linkage editor.
The remedy is a generated #define prologue that gives every external a compliant name. It is applied on x86 as well as on MVS, so the ordinary test suite exercises the renaming mechanism instead of leaving MVS to discover it.
Five names a #define would have deleted rather than renamed
Release 3e needed the same treatment for its own build, and five of its thirteen colliding names could not take it. Each is written #ifndef <name> in primitives.h and again in its own source file. That is upstream's documented extension point, where defining the name declares that the platform supplies the function, and upstream then omits both the declaration and the definition.
A rename macro would therefore have removed those five functions. ONFLY uses the extension point as designed: softfloat/onfprim.c carries upstream's own bodies under compliant names, derived mechanically by a script, with third_party/ untouched.
Copying a function body does not prove the copy behaves identically. The evidence is the golden acceptance fingerprints, computed before any of this existed, which would move if a primitive changed.
The lint that listed the collision for weeks and enforced nothing
The project's C-04 lint had been reporting SoftFloat's over-length externals since before the port began, while enforcing only on names ONFLY itself defines. That is how Release 2c reached Assembler XF before anyone noticed. It now enforces, and run against the unrenamed object it reproduces the same three groups the assembler found.
The failure it guards against is the quiet one. Two names that differ only after character 8, or only in case, are the same symbol to the MVS linkage editor, which links cleanly and calls the wrong function.
Agreement between the two SoftFloat releases was settled before either was ported, on x86, against Berkeley TestFloat rather than against each other: 260,376 cases across six operations, zero mismatches, 18,408 NaN cases excluded (TestFloat). Two libraries agreeing with an independent oracle says more than two agreeing between themselves.
What has actually been compiled on MVS so far
The float library and three test drivers run on MVS 3.8j TK5 under Hercules. No ONFLY engine code has been built there yet: the engine, the kernel, the decoder and the request loop have all been exercised elsewhere. The MVS TestFloat run covers 4,500 cases against x86's 260,376, stratified rather than a prefix, and still a sample.
Four workarounds are load bearing and none of them lives in the repository: the -O1 pin that threads between two distinct compiler bugs, the Hercules 819/1047 codepage, the include amalgamation and the symbol renames. A Hercules restart silently reverts the codepage, so the submit tool refuses to send a job when it has.
Browse the C-04 lint and the rename generators in the ONFLY repository if you are porting anything to a PDS-based toolchain; the eight-character rule will find you before your test suite does.