Files
arti 6338095683 tools: add as34/ld34 TMS34010 binutils, ported to 64-bit Linux
Andrew Morton's Unix-hosted assembler/linker for the TMS34010, fetched from the gsptools archive and patched to build on x86-64. The K&R sources silently truncate pointers there: implicit int parameter declarations and fixed-argument printf wrappers. The patch fixes those and the flex 2.6 yy_init mismatch.

hello.as34.g is harness/hello-world/hello.asm in as34 syntax. as34/ld34 reproduce the GSPA-built payload byte-for-byte (82 bytes, md5 db91788991ebba476b55a11127a36475), and the MAME hello.lua run reports the same markers, the same 1024-word VRAM block and a byte-identical frame.

build.sh downloads the upstream tarball at build time (sha256 pinned); the tree is not vendored.
2026-10-22 14:19:14 +03:00
..

as34 / ld34 — Morton's Unix-hosted TMS34010 binutils

as34 (assembler) and ld34 (linker) are Andrew Morton's 1990s TMS34010 tools, shipped with his GCC 2.5.x port. They are not TI tools and not related to GSPA/GSPLNK; they run natively on Linux, with no DOSBox.

build.sh fetches the original gsp.tar.gz from the Wayback Machine, applies as34-port.patch, and builds three programs:

tool what it does
as34 assembles .g source to a .go object (LINKMAGIC 0x3abf782e)
ld34 links .go objects to g.out (same linkhdr container), with a map
dis34 disassembles g.out (kept for inspection; the repo's tools/smart34010/dis34 is a better independent decoder)

The compiled .text is extracted from g.out by extract.py. g.out is not COFF — ld34/coff.c is dead code that is neither compiled nor called. The live writer is ld34/header.c, which emits the same packed linkhdr format that as34 produces.

Build

tools/as34/build.sh

Everything is fetched and built under tools/as34/build/ (git-ignored; override with AS34_BUILD_DIR). The tools end up at:

tools/as34/build/src/gsp/binutils/as34/as34
tools/as34/build/src/gsp/binutils/ld34/ld34
tools/as34/build/src/gsp/binutils/ld34/dis34

The tarball is 2.1 MB and is an uncompressed tar with a .tar.gz name — that is how the archive is stored. Its SHA-256 is pinned in build.sh.

Test (byte comparison, then MAME)

tools/as34/test.sh
REPO=$PWD MAME=/home/arti/code/k-space/mame0289/vt1200 tools/as34/test.sh

hello.as34.g is harness/hello-world/hello.asm ported to as34 syntax. The result is byte-identical to the GSPA-built harness/hello-world/payload.bin (82 bytes, md5 db91788991ebba476b55a11127a36475), and the MAME run reports the same markers, the same 1024-word VRAM block and the same frame as the original payload.

Syntax differences from GSPA

GSPA as34
hex 0DEADh >DEAD (also 0xdead)
immediate width movi x, a0, L no L/W suffix; movi is always the 32-bit form
16-bit immediate add addi addiw — as34's addi is the 32-bit immediate form
immediate order same (op src, dst) same

Everything else — labels, @absolute, *a2+, dsjs, bit addresses, field specifiers — is unchanged. dsjs displacement encoding matches GSPA (checked against tools/smart34010/dis34).

What the port patch changes

The code is K&R C written for 32-bit SunOS. On x86-64 the original build produces truncated pointers, so the patch is not cosmetic:

  • Pointer parameters declared implicitly as int (Xwrite, openfiles, emitslcode/emitnslcode/emitswcode/emitnswcode). On a 32-bit host the implicit int happened to be pointer-sized; on x86-64 it truncates.
  • K&R printf wrappers (amprintf, ameprintf, amfprintf, eprintf) declared p1…p6 as int, truncating %s arguments. Rewritten as real variadic functions with va_list.
  • imalloc likewise made variadic, and declared in proto.h (included with -include for the assembler's translation units).
  • flex 2.6: yyGetReady() used to set yy_init = 1; with the modern skeleton that leaves yy_c_buf_p NULL and segfaults. It is now a no-op — YY_INPUT/am_input still supplies the line buffer.
  • abort(1) → abort(); hash() uses unsigned arithmetic; two exit(eprintf(...)) calls split.

Upstream quirks worth knowing

  • -e takes its argument attached: -e_start. The space form (-e _start) is broken in the original parser: it sets the entry name to the empty string and treats _start as an object file.
  • The container format depends on the host long size. link.h stores addresses and sizes as long; this build writes 8-byte fields, so the header is 156 bytes rather than the historical 80. as34, ld34 and extract.py all agree, but these files are not interchangeable with 32-bit-host g.out files. Making the format stable would mean changing long to int32_t in link.h.
  • ld34 runs as34 from PATH when generating C++ ctor/dtor tables. test.sh passes -c to skip that.
  • as34 is not GSPA-compatible at the token level (see the table above).

Licence

The upstream tarball contains GPLv2-era GNU binutils code plus Morton's own sources. It is downloaded at build time, not vendored here; the patch is the only derived file committed.