cmd: add new common architecture representation

Information about CPU architectures (e.g., name, family, byte
ordering, pointer and register size) is currently redundantly
scattered around the source tree. Instead consolidate the basic
information into a single new package cmd/internal/sys.

Also, introduce new sys.I386, sys.AMD64, etc. names for the constants
'8', '6', etc. and replace most uses of the latter. The notable
exceptions are a couple of error messages that still refer to the old
char-based toolchain names and function reltype in cmd/link.

Passes toolstash/buildall.

Change-Id: I8a6f0cbd49577ec1672a98addebc45f767e36461
Reviewed-on: https://go-review.googlesource.com/21623
Reviewed-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go
index 950fd73..d674914 100644
--- a/src/cmd/asm/internal/asm/asm.go
+++ b/src/cmd/asm/internal/asm/asm.go
@@ -13,6 +13,7 @@
 	"cmd/asm/internal/flags"
 	"cmd/asm/internal/lex"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 )
 
 // TODO: configure the architecture
@@ -23,14 +24,14 @@
 // If doLabel is set, it also defines the labels collect for this Prog.
 func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
 	if cond != "" {
-		switch p.arch.Thechar {
-		case '5':
+		switch p.arch.Family {
+		case sys.ARM:
 			if !arch.ARMConditionCodes(prog, cond) {
 				p.errorf("unrecognized condition code .%q", cond)
 				return
 			}
 
-		case '7':
+		case sys.ARM64:
 			if !arch.ARM64Suffix(prog, cond) {
 				p.errorf("unrecognized suffix .%q", cond)
 				return
@@ -361,7 +362,7 @@
 		target = &a[1]
 		prog.From = a[0]
 	case 3:
-		if p.arch.Thechar == '9' {
+		if p.arch.Family == sys.PPC64 {
 			// Special 3-operand jumps.
 			// First two must be constants; a[1] is a register number.
 			target = &a[2]
@@ -378,7 +379,7 @@
 			prog.Reg = reg
 			break
 		}
-		if p.arch.Thechar == '0' {
+		if p.arch.Family == sys.MIPS64 {
 			// 3-operand jumps.
 			// First two must be registers
 			target = &a[2]
@@ -386,7 +387,7 @@
 			prog.Reg = p.getRegister(prog, op, &a[1])
 			break
 		}
-		if p.arch.Thechar == 'z' {
+		if p.arch.Family == sys.S390X {
 			// 3-operand jumps.
 			target = &a[2]
 			prog.From = a[0]
@@ -438,7 +439,7 @@
 		// JMP 4(R0)
 		prog.To = *target
 		// On the ppc64, 9a encodes BR (CTR) as BR CTR. We do the same.
-		if p.arch.Thechar == '9' && target.Offset == 0 {
+		if p.arch.Family == sys.PPC64 && target.Offset == 0 {
 			prog.To.Type = obj.TYPE_REG
 		}
 	case target.Type == obj.TYPE_CONST:
@@ -492,14 +493,14 @@
 			prog.From = a[0]
 			// prog.To is no address.
 		}
-		if p.arch.Thechar == '9' && arch.IsPPC64NEG(op) {
+		if p.arch.Family == sys.PPC64 && arch.IsPPC64NEG(op) {
 			// NEG: From and To are both a[0].
 			prog.To = a[0]
 			prog.From = a[0]
 			break
 		}
 	case 2:
-		if p.arch.Thechar == '5' {
+		if p.arch.Family == sys.ARM {
 			if arch.IsARMCMP(op) {
 				prog.From = a[0]
 				prog.Reg = p.getRegister(prog, op, &a[1])
@@ -532,11 +533,11 @@
 				prog.Reg = p.getRegister(prog, op, &a[1])
 				break
 			}
-		} else if p.arch.Thechar == '7' && arch.IsARM64CMP(op) {
+		} else if p.arch.Family == sys.ARM64 && arch.IsARM64CMP(op) {
 			prog.From = a[0]
 			prog.Reg = p.getRegister(prog, op, &a[1])
 			break
-		} else if p.arch.Thechar == '0' {
+		} else if p.arch.Family == sys.MIPS64 {
 			if arch.IsMIPS64CMP(op) || arch.IsMIPS64MUL(op) {
 				prog.From = a[0]
 				prog.Reg = p.getRegister(prog, op, &a[1])
@@ -546,12 +547,12 @@
 		prog.From = a[0]
 		prog.To = a[1]
 	case 3:
-		switch p.arch.Thechar {
-		case '0':
+		switch p.arch.Family {
+		case sys.MIPS64:
 			prog.From = a[0]
 			prog.Reg = p.getRegister(prog, op, &a[1])
 			prog.To = a[2]
-		case '5':
+		case sys.ARM:
 			// Special cases.
 			if arch.IsARMSTREX(op) {
 				/*
@@ -567,7 +568,7 @@
 			prog.From = a[0]
 			prog.Reg = p.getRegister(prog, op, &a[1])
 			prog.To = a[2]
-		case '7':
+		case sys.ARM64:
 			// ARM64 instructions with one input and two outputs.
 			if arch.IsARM64STLXR(op) {
 				prog.From = a[0]
@@ -582,11 +583,11 @@
 			prog.From = a[0]
 			prog.Reg = p.getRegister(prog, op, &a[1])
 			prog.To = a[2]
-		case '6', '8':
+		case sys.AMD64, sys.I386:
 			prog.From = a[0]
 			prog.From3 = newAddr(a[1])
 			prog.To = a[2]
-		case '9':
+		case sys.PPC64:
 			if arch.IsPPC64CMP(op) {
 				// CMPW etc.; third argument is a CR register that goes into prog.Reg.
 				prog.From = a[0]
@@ -612,7 +613,7 @@
 				p.errorf("invalid addressing modes for %s instruction", obj.Aconv(op))
 				return
 			}
-		case 'z':
+		case sys.S390X:
 			if arch.IsS390xWithLength(op) || arch.IsS390xWithIndex(op) {
 				prog.From = a[1]
 				prog.From3 = newAddr(a[0])
@@ -626,7 +627,7 @@
 			return
 		}
 	case 4:
-		if p.arch.Thechar == '5' && arch.IsARMMULA(op) {
+		if p.arch.Family == sys.ARM && arch.IsARMMULA(op) {
 			// All must be registers.
 			p.getRegister(prog, op, &a[0])
 			r1 := p.getRegister(prog, op, &a[1])
@@ -639,14 +640,14 @@
 			prog.Reg = r1
 			break
 		}
-		if p.arch.Thechar == '7' {
+		if p.arch.Family == sys.ARM64 {
 			prog.From = a[0]
 			prog.Reg = p.getRegister(prog, op, &a[1])
 			prog.From3 = newAddr(a[2])
 			prog.To = a[3]
 			break
 		}
-		if p.arch.Thechar == '9' && arch.IsPPC64RLD(op) {
+		if p.arch.Family == sys.PPC64 && arch.IsPPC64RLD(op) {
 			// 2nd operand must always be a register.
 			// TODO: Do we need to guard this with the instruction type?
 			// That is, are there 4-operand instructions without this property?
@@ -656,7 +657,7 @@
 			prog.To = a[3]
 			break
 		}
-		if p.arch.Thechar == 'z' {
+		if p.arch.Family == sys.S390X {
 			prog.From = a[1]
 			prog.Reg = p.getRegister(prog, op, &a[2])
 			prog.From3 = newAddr(a[0])
@@ -666,7 +667,7 @@
 		p.errorf("can't handle %s instruction with 4 operands", obj.Aconv(op))
 		return
 	case 5:
-		if p.arch.Thechar == '9' && arch.IsPPC64RLD(op) {
+		if p.arch.Family == sys.PPC64 && arch.IsPPC64RLD(op) {
 			// Always reg, reg, con, con, reg.  (con, con is a 'mask').
 			prog.From = a[0]
 			prog.Reg = p.getRegister(prog, op, &a[1])
@@ -688,7 +689,7 @@
 		p.errorf("can't handle %s instruction with 5 operands", obj.Aconv(op))
 		return
 	case 6:
-		if p.arch.Thechar == '5' && arch.IsARMMRC(op) {
+		if p.arch.Family == sys.ARM && arch.IsARMMRC(op) {
 			// Strange special case: MCR, MRC.
 			prog.To.Type = obj.TYPE_CONST
 			x0 := p.getConstant(prog, op, &a[0])
diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go
index ee37439..40206e6 100644
--- a/src/cmd/asm/internal/asm/parse.go
+++ b/src/cmd/asm/internal/asm/parse.go
@@ -19,6 +19,7 @@
 	"cmd/asm/internal/flags"
 	"cmd/asm/internal/lex"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 )
 
 type Parser struct {
@@ -130,7 +131,7 @@
 		for {
 			tok = p.lex.Next()
 			if len(operands) == 0 && len(items) == 0 {
-				if (p.arch.Thechar == '5' || p.arch.Thechar == '7') && tok == '.' {
+				if p.arch.InFamily(sys.ARM, sys.ARM64) && tok == '.' {
 					// ARM conditionals.
 					tok = p.lex.Next()
 					str := p.lex.Text()
@@ -420,7 +421,7 @@
 // We have consumed the register or R prefix.
 func (p *Parser) atRegisterShift() bool {
 	// ARM only.
-	if p.arch.Thechar != '5' {
+	if p.arch.Family != sys.ARM {
 		return false
 	}
 	// R1<<...
@@ -476,15 +477,14 @@
 	if c == ':' || c == ',' || c == '+' {
 		// 2nd register; syntax (R1+R2) etc. No two architectures agree.
 		// Check the architectures match the syntax.
-		char := p.arch.Thechar
 		switch p.next().ScanToken {
 		case ',':
-			if char != '5' && char != '7' {
+			if !p.arch.InFamily(sys.ARM, sys.ARM64) {
 				p.errorf("(register,register) not supported on this architecture")
 				return
 			}
 		case '+':
-			if char != '9' {
+			if p.arch.Family != sys.PPC64 {
 				p.errorf("(register+register) not supported on this architecture")
 				return
 			}
@@ -649,7 +649,7 @@
 	a.Reg = r1
 	if r2 != 0 {
 		// TODO: Consistency in the encoding would be nice here.
-		if p.arch.Thechar == '5' || p.arch.Thechar == '7' {
+		if p.arch.InFamily(sys.ARM, sys.ARM64) {
 			// Special form
 			// ARM: destination register pair (R1, R2).
 			// ARM64: register pair (R1, R2) for LDP/STP.
@@ -662,7 +662,7 @@
 			// Nothing may follow
 			return
 		}
-		if p.arch.Thechar == '9' {
+		if p.arch.Family == sys.PPC64 {
 			// Special form for PPC64: (R1+R2); alias for (R1)(R2*1).
 			if prefix != 0 || scale != 0 {
 				p.errorf("illegal address mode for register+register")
@@ -752,7 +752,7 @@
 
 // register number is ARM-specific. It returns the number of the specified register.
 func (p *Parser) registerNumber(name string) uint16 {
-	if p.arch.Thechar == '5' && name == "g" {
+	if p.arch.Family == sys.ARM && name == "g" {
 		return 10
 	}
 	if name[0] != 'R' {
diff --git a/src/cmd/compile/internal/amd64/galign.go b/src/cmd/compile/internal/amd64/galign.go
index 14721ea..461ef2a 100644
--- a/src/cmd/compile/internal/amd64/galign.go
+++ b/src/cmd/compile/internal/amd64/galign.go
@@ -18,12 +18,7 @@
 )
 
 func betypeinit() {
-	gc.Widthptr = 8
-	gc.Widthint = 8
-	gc.Widthreg = 8
 	if obj.Getgoarch() == "amd64p32" {
-		gc.Widthptr = 4
-		gc.Widthint = 4
 		addptr = x86.AADDL
 		movptr = x86.AMOVL
 		leaptr = x86.ALEAL
@@ -42,12 +37,9 @@
 		resvd = append(resvd, x86.REG_BP)
 	}
 
-	gc.Thearch.Thechar = '6'
-	gc.Thearch.Thestring = "amd64"
-	gc.Thearch.Thelinkarch = &x86.Linkamd64
+	gc.Thearch.LinkArch = &x86.Linkamd64
 	if obj.Getgoarch() == "amd64p32" {
-		gc.Thearch.Thestring = "amd64p32"
-		gc.Thearch.Thelinkarch = &x86.Linkamd64p32
+		gc.Thearch.LinkArch = &x86.Linkamd64p32
 	}
 	gc.Thearch.REGSP = x86.REGSP
 	gc.Thearch.REGCTXT = x86.REGCTXT
diff --git a/src/cmd/compile/internal/arm/galign.go b/src/cmd/compile/internal/arm/galign.go
index e05f4d0..afd86e4 100644
--- a/src/cmd/compile/internal/arm/galign.go
+++ b/src/cmd/compile/internal/arm/galign.go
@@ -11,15 +11,10 @@
 )
 
 func betypeinit() {
-	gc.Widthptr = 4
-	gc.Widthint = 4
-	gc.Widthreg = 4
 }
 
 func Main() {
-	gc.Thearch.Thechar = '5'
-	gc.Thearch.Thestring = "arm"
-	gc.Thearch.Thelinkarch = &arm.Linkarm
+	gc.Thearch.LinkArch = &arm.Linkarm
 	gc.Thearch.REGSP = arm.REGSP
 	gc.Thearch.REGCTXT = arm.REGCTXT
 	gc.Thearch.REGCALLX = arm.REG_R1
diff --git a/src/cmd/compile/internal/arm64/galign.go b/src/cmd/compile/internal/arm64/galign.go
index 7e1226f..17c851c 100644
--- a/src/cmd/compile/internal/arm64/galign.go
+++ b/src/cmd/compile/internal/arm64/galign.go
@@ -10,15 +10,10 @@
 )
 
 func betypeinit() {
-	gc.Widthptr = 8
-	gc.Widthint = 8
-	gc.Widthreg = 8
 }
 
 func Main() {
-	gc.Thearch.Thechar = '7'
-	gc.Thearch.Thestring = "arm64"
-	gc.Thearch.Thelinkarch = &arm64.Linkarm64
+	gc.Thearch.LinkArch = &arm64.Linkarm64
 	gc.Thearch.REGSP = arm64.REGSP
 	gc.Thearch.REGCTXT = arm64.REGCTXT
 	gc.Thearch.REGCALLX = arm64.REGRT1
diff --git a/src/cmd/compile/internal/gc/cgen.go b/src/cmd/compile/internal/gc/cgen.go
index c594ad4..a9cedf7 100644
--- a/src/cmd/compile/internal/gc/cgen.go
+++ b/src/cmd/compile/internal/gc/cgen.go
@@ -7,6 +7,7 @@
 import (
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
+	"cmd/internal/sys"
 	"fmt"
 )
 
@@ -88,7 +89,7 @@
 
 	if !res.Addable {
 		if n.Ullman > res.Ullman {
-			if Ctxt.Arch.Regsize == 4 && Is64(n.Type) {
+			if Ctxt.Arch.RegSize == 4 && Is64(n.Type) {
 				var n1 Node
 				Tempname(&n1, n.Type)
 				Cgen(n, &n1)
@@ -127,7 +128,7 @@
 				f = false
 			}
 
-			if !n.Type.IsComplex() && Ctxt.Arch.Regsize == 8 && !wb {
+			if !n.Type.IsComplex() && Ctxt.Arch.RegSize == 8 && !wb {
 				a := Thearch.Optoas(OAS, res.Type)
 				var addr obj.Addr
 				if Thearch.Sudoaddable(a, res, &addr) {
@@ -151,7 +152,7 @@
 			}
 		}
 
-		if Ctxt.Arch.Thechar == '8' {
+		if Ctxt.Arch.Family == sys.I386 {
 			// no registers to speak of
 			var n1, n2 Node
 			Tempname(&n1, n.Type)
@@ -203,7 +204,7 @@
 
 	// Write barrier now handled. Code below this line can ignore wb.
 
-	if Ctxt.Arch.Thechar == '5' { // TODO(rsc): Maybe more often?
+	if Ctxt.Arch.Family == sys.ARM { // TODO(rsc): Maybe more often?
 		// if both are addressable, move
 		if n.Addable && res.Addable {
 			if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || n.Type.IsComplex() || res.Type.IsComplex() {
@@ -246,12 +247,12 @@
 		return
 	}
 
-	if (Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8') && n.Addable {
+	if Ctxt.Arch.InFamily(sys.AMD64, sys.I386) && n.Addable {
 		Thearch.Gmove(n, res)
 		return
 	}
 
-	if Ctxt.Arch.Thechar == '0' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
+	if Ctxt.Arch.InFamily(sys.ARM64, sys.MIPS64, sys.PPC64) {
 		// if both are addressable, move
 		if n.Addable {
 			if n.Op == OREGISTER || res.Op == OREGISTER {
@@ -268,7 +269,7 @@
 	}
 
 	// if n is sudoaddable generate addr and move
-	if Ctxt.Arch.Thechar == '5' && !Is64(n.Type) && !Is64(res.Type) && !n.Type.IsComplex() && !res.Type.IsComplex() {
+	if Ctxt.Arch.Family == sys.ARM && !Is64(n.Type) && !Is64(res.Type) && !n.Type.IsComplex() && !res.Type.IsComplex() {
 		a := Thearch.Optoas(OAS, n.Type)
 		var addr obj.Addr
 		if Thearch.Sudoaddable(a, n, &addr) {
@@ -310,7 +311,7 @@
 	}
 
 	// 64-bit ops are hard on 32-bit machine.
-	if Ctxt.Arch.Regsize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) {
+	if Ctxt.Arch.RegSize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) {
 		switch n.Op {
 		// math goes to cgen64.
 		case OMINUS,
@@ -334,7 +335,7 @@
 		return
 	}
 
-	if !n.Type.IsComplex() && Ctxt.Arch.Regsize == 8 {
+	if !n.Type.IsComplex() && Ctxt.Arch.RegSize == 8 {
 		a := Thearch.Optoas(OAS, n.Type)
 		var addr obj.Addr
 		if Thearch.Sudoaddable(a, n, &addr) {
@@ -401,11 +402,11 @@
 		Regalloc(&n1, nl.Type, res)
 
 		Cgen(nl, &n1)
-		if Ctxt.Arch.Thechar == '5' {
+		if Ctxt.Arch.Family == sys.ARM {
 			var n2 Node
 			Nodconst(&n2, nl.Type, 0)
 			Thearch.Gins(a, &n2, &n1)
-		} else if Ctxt.Arch.Thechar == '7' {
+		} else if Ctxt.Arch.Family == sys.ARM64 {
 			Thearch.Gins(a, &n1, &n1)
 		} else {
 			Thearch.Gins(a, nil, &n1)
@@ -452,7 +453,7 @@
 			return
 		}
 
-		if Ctxt.Arch.Thechar == '8' {
+		if Ctxt.Arch.Family == sys.I386 {
 			var n1 Node
 			var n2 Node
 			Tempname(&n2, n.Type)
@@ -465,7 +466,7 @@
 
 		var n1 Node
 		var n2 Node
-		if Ctxt.Arch.Thechar == '5' {
+		if Ctxt.Arch.Family == sys.ARM {
 			if nl.Addable && !Is64(nl.Type) {
 				Regalloc(&n1, nl.Type, res)
 				Thearch.Gmove(nl, &n1)
@@ -707,7 +708,7 @@
 abop: // asymmetric binary
 	var n1 Node
 	var n2 Node
-	if Ctxt.Arch.Thechar == '8' {
+	if Ctxt.Arch.Family == sys.I386 {
 		// no registers, sigh
 		if Smallintconst(nr) {
 			var n1 Node
@@ -751,14 +752,14 @@
 		Regalloc(&n1, nl.Type, res)
 		Cgen(nl, &n1)
 
-		if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
+		if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.ARM && Ctxt.Arch.Family != sys.ARM64 && Ctxt.Arch.Family != sys.PPC64 { // TODO(rsc): Check opcode for arm
 			n2 = *nr
 		} else {
 			Regalloc(&n2, nr.Type, nil)
 			Cgen(nr, &n2)
 		}
 	} else {
-		if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm
+		if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.ARM && Ctxt.Arch.Family != sys.ARM64 && Ctxt.Arch.Family != sys.PPC64 { // TODO(rsc): Check opcode for arm
 			n2 = *nr
 		} else {
 			Regalloc(&n2, nr.Type, res)
@@ -876,8 +877,8 @@
 // cgen_norm moves n1 to res, truncating to expected type if necessary.
 // n1 is a register, and cgen_norm frees it.
 func cgen_norm(n, n1, res *Node) {
-	switch Ctxt.Arch.Thechar {
-	case '6', '8':
+	switch Ctxt.Arch.Family {
+	case sys.AMD64, sys.I386:
 		// We use sized math, so the result is already truncated.
 	default:
 		switch n.Op {
@@ -980,7 +981,7 @@
 		Cgen_checknil(a)
 
 	case OINDEX:
-		if Ctxt.Arch.Thechar == '5' {
+		if Ctxt.Arch.Family == sys.ARM {
 			var p2 *obj.Prog // to be patched to panicindex.
 			w := uint32(n.Type.Width)
 			bounded := Debug['B'] != 0 || n.Bounded
@@ -1127,7 +1128,7 @@
 			Regfree(&n2)
 			break
 		}
-		if Ctxt.Arch.Thechar == '8' {
+		if Ctxt.Arch.Family == sys.I386 {
 			var p2 *obj.Prog // to be patched to panicindex.
 			w := uint32(n.Type.Width)
 			bounded := Debug['B'] != 0 || n.Bounded
@@ -1604,7 +1605,7 @@
 }
 
 func addOffset(res *Node, offset int64) {
-	if Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8' {
+	if Ctxt.Arch.InFamily(sys.AMD64, sys.I386) {
 		Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), Nodintconst(offset), res)
 		return
 	}
@@ -1825,13 +1826,14 @@
 		return
 
 	case ONAME:
+		// Some architectures might need a temporary or other help here,
+		// but they don't support direct generation of a bool value yet.
+		// We can fix that as we go.
+		mayNeedTemp := Ctxt.Arch.InFamily(sys.ARM, sys.ARM64, sys.MIPS64, sys.PPC64)
+
 		if genval {
-			// 5g, 7g, and 9g might need a temporary or other help here,
-			// but they don't support direct generation of a bool value yet.
-			// We can fix that as we go.
-			switch Ctxt.Arch.Thechar {
-			case '0', '5', '7', '9':
-				Fatalf("genval 0g, 5g, 7g, 9g ONAMES not fully implemented")
+			if mayNeedTemp {
+				Fatalf("genval ONAMES not fully implemented")
 			}
 			Cgen(n, res)
 			if !wantTrue {
@@ -1840,7 +1842,7 @@
 			return
 		}
 
-		if n.Addable && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' {
+		if n.Addable && !mayNeedTemp {
 			// no need for a temporary
 			bgenNonZero(n, nil, wantTrue, likely, to)
 			return
@@ -1977,7 +1979,7 @@
 		return
 	}
 
-	if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) {
+	if Ctxt.Arch.RegSize == 4 && Is64(nr.Type) {
 		if genval {
 			// TODO: Teach Cmp64 to generate boolean values and remove this.
 			bvgenjump(n, res, wantTrue, false)
@@ -2015,7 +2017,7 @@
 		Regfree(&n2)
 	} else {
 		var n1 Node
-		if !nl.Addable && Ctxt.Arch.Thechar == '8' {
+		if !nl.Addable && Ctxt.Arch.Family == sys.I386 {
 			Tempname(&n1, nl.Type)
 		} else {
 			Regalloc(&n1, nl.Type, nil)
@@ -2024,13 +2026,13 @@
 		Cgen(nl, &n1)
 		nl = &n1
 
-		if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '9' {
+		if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.PPC64 {
 			Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr)
 			bins(nr.Type, res, op, likely, to)
 			return
 		}
 
-		if !nr.Addable && Ctxt.Arch.Thechar == '8' {
+		if !nr.Addable && Ctxt.Arch.Family == sys.I386 {
 			nr = CgenTemp(nr)
 		}
 
@@ -2044,13 +2046,13 @@
 	l, r := nl, nr
 
 	// On x86, only < and <= work right with NaN; reverse if needed
-	if Ctxt.Arch.Thechar == '6' && nl.Type.IsFloat() && (op == OGT || op == OGE) {
+	if Ctxt.Arch.Family == sys.AMD64 && nl.Type.IsFloat() && (op == OGT || op == OGE) {
 		l, r = r, l
 		op = Brrev(op)
 	}
 
 	// MIPS does not have CMP instruction
-	if Ctxt.Arch.Thechar == '0' {
+	if Ctxt.Arch.Family == sys.MIPS64 {
 		p := Thearch.Ginscmp(op, nr.Type, l, r, likely)
 		Patch(p, to)
 		return
@@ -2062,8 +2064,8 @@
 	// Handle floating point special cases.
 	// Note that 8g has Bgen_float and is handled above.
 	if nl.Type.IsFloat() {
-		switch Ctxt.Arch.Thechar {
-		case '5':
+		switch Ctxt.Arch.Family {
+		case sys.ARM:
 			if genval {
 				Fatalf("genval 5g Isfloat special cases not implemented")
 			}
@@ -2077,7 +2079,7 @@
 				Patch(p, Pc)
 			}
 			return
-		case '6':
+		case sys.AMD64:
 			switch n.Op {
 			case OEQ:
 				// neither NE nor P
@@ -2111,7 +2113,7 @@
 				}
 				return
 			}
-		case '7', '9':
+		case sys.ARM64, sys.PPC64:
 			if genval {
 				Fatalf("genval 7g, 9g Isfloat special cases not implemented")
 			}
@@ -2143,7 +2145,7 @@
 	}
 
 	// MIPS does not have CMP instruction
-	if Thearch.Thechar == '0' {
+	if Thearch.LinkArch.Family == sys.MIPS64 {
 		p := Gbranch(Thearch.Optoas(op, n.Type), n.Type, likely)
 		Naddr(&p.From, n)
 		Patch(p, to)
@@ -2352,7 +2354,7 @@
 				// into the instruction stream.
 				Thearch.Ginsnop()
 
-				if Thearch.Thechar == '9' {
+				if Thearch.LinkArch.Family == sys.PPC64 {
 					// On ppc64, when compiling Go into position
 					// independent code on ppc64le we insert an
 					// instruction to reload the TOC pointer from the
@@ -2630,7 +2632,7 @@
 	// in peep and optoas in order to enable this.
 	// TODO(rsc): ppc64 needs to support the relevant instructions
 	// in peep and optoas in order to enable this.
-	if nr.Op != OLITERAL || Ctxt.Arch.Thechar == '0' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
+	if nr.Op != OLITERAL || Ctxt.Arch.Family == sys.MIPS64 || Ctxt.Arch.Family == sys.ARM64 || Ctxt.Arch.Family == sys.PPC64 {
 		goto longdiv
 	}
 	w = int(nl.Type.Width * 8)
@@ -2995,7 +2997,7 @@
 	regalloc := Regalloc
 	ginscon := Thearch.Ginscon
 	gins := Thearch.Gins
-	if Thearch.Thechar == '8' {
+	if Thearch.LinkArch.Family == sys.I386 {
 		regalloc = func(n *Node, t *Type, reuse *Node) {
 			Tempname(n, t)
 		}
@@ -3238,7 +3240,7 @@
 	compare := func(n1, n2 *Node) {
 		// n1 might be a 64-bit constant, even on 32-bit architectures,
 		// but it will be represented in 32 bits.
-		if Ctxt.Arch.Regsize == 4 && Is64(n1.Type) {
+		if Ctxt.Arch.RegSize == 4 && Is64(n1.Type) {
 			if n1.Val().U.(*Mpint).CmpInt64(1<<31) >= 0 {
 				Fatalf("missed slice out of bounds check")
 			}
diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go
index 4a98f41..7527452 100644
--- a/src/cmd/compile/internal/gc/gen.go
+++ b/src/cmd/compile/internal/gc/gen.go
@@ -8,6 +8,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 )
 
@@ -1174,7 +1175,7 @@
 		}
 		// NOTE: Assuming little endian (signed top half at offset 4).
 		// We don't have any 32-bit big-endian systems.
-		if Thearch.Thechar != '5' && Thearch.Thechar != '8' {
+		if !Thearch.LinkArch.InFamily(sys.ARM, sys.I386) {
 			Fatalf("unknown 32-bit architecture")
 		}
 		return f(Types[TUINT32], startOffset) &&
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index 4cb985b..ef8b516 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -360,9 +360,8 @@
 )
 
 type Arch struct {
-	Thechar      int
-	Thestring    string
-	Thelinkarch  *obj.LinkArch
+	LinkArch *obj.LinkArch
+
 	REGSP        int
 	REGCTXT      int
 	REGCALLX     int // BX
diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go
index a2fa5f8..63a8e96 100644
--- a/src/cmd/compile/internal/gc/gsubr.go
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -32,6 +32,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"runtime"
 	"strings"
@@ -57,7 +58,7 @@
 		return true
 
 	case OADDR:
-		return Thearch.Thechar == '6' || Thearch.Thechar == '9' // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too
+		return Thearch.LinkArch.InFamily(sys.AMD64, sys.PPC64) // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too
 	}
 
 	return false
@@ -83,7 +84,7 @@
 	p := Prog(as)
 	p.To.Type = obj.TYPE_BRANCH
 	p.To.Val = nil
-	if as != obj.AJMP && likely != 0 && Thearch.Thechar != '9' && Thearch.Thechar != '7' && Thearch.Thechar != '0' {
+	if as != obj.AJMP && likely != 0 && Thearch.LinkArch.Family != sys.PPC64 && Thearch.LinkArch.Family != sys.ARM64 && Thearch.LinkArch.Family != sys.MIPS64 {
 		p.From.Type = obj.TYPE_CONST
 		if likely > 0 {
 			p.From.Offset = 1
@@ -330,7 +331,7 @@
 		a.Type = obj.TYPE_REG
 		a.Reg = n.Reg
 		a.Sym = nil
-		if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width.
+		if Thearch.LinkArch.Family == sys.I386 { // TODO(rsc): Never clear a->width.
 			a.Width = 0
 		}
 
@@ -342,7 +343,7 @@
 		if a.Offset != int64(int32(a.Offset)) {
 			Yyerror("offset %d too large for OINDREG", a.Offset)
 		}
-		if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width.
+		if Thearch.LinkArch.Family == sys.I386 { // TODO(rsc): Never clear a->width.
 			a.Width = 0
 		}
 
@@ -424,7 +425,7 @@
 		Naddr(a, n.Left)
 
 	case OLITERAL:
-		if Thearch.Thechar == '8' {
+		if Thearch.LinkArch.Family == sys.I386 {
 			a.Width = 0
 		}
 		switch n.Val().Ctype() {
@@ -457,7 +458,7 @@
 	case OADDR:
 		Naddr(a, n.Left)
 		a.Etype = uint8(Tptr)
-		if Thearch.Thechar != '0' && Thearch.Thechar != '5' && Thearch.Thechar != '7' && Thearch.Thechar != '9' { // TODO(rsc): Do this even for arm, ppc64.
+		if !Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) { // TODO(rsc): Do this even for arm, ppc64.
 			a.Width = int64(Widthptr)
 		}
 		if a.Type != obj.TYPE_MEM {
@@ -496,7 +497,7 @@
 		}
 		a.Etype = uint8(Simtype[TUINT])
 		a.Offset += int64(Array_nel)
-		if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm.
+		if Thearch.LinkArch.Family != sys.ARM { // TODO(rsc): Do this even on arm.
 			a.Width = int64(Widthint)
 		}
 
@@ -509,7 +510,7 @@
 		}
 		a.Etype = uint8(Simtype[TUINT])
 		a.Offset += int64(Array_cap)
-		if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm.
+		if Thearch.LinkArch.Family != sys.ARM { // TODO(rsc): Do this even on arm.
 			a.Width = int64(Widthint)
 		}
 	}
@@ -695,7 +696,7 @@
 		Fatalf("regalloc: t nil")
 	}
 	et := Simtype[t.Etype]
-	if Ctxt.Arch.Regsize == 4 && (et == TINT64 || et == TUINT64) {
+	if Ctxt.Arch.RegSize == 4 && (et == TINT64 || et == TUINT64) {
 		Fatalf("regalloc 64bit")
 	}
 
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index 73ecb09..72e6478 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -10,6 +10,7 @@
 	"bufio"
 	"cmd/compile/internal/ssa"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"flag"
 	"fmt"
 	"io"
@@ -96,12 +97,12 @@
 	// but not other values.
 	p := obj.Getgoarch()
 
-	if !strings.HasPrefix(p, Thearch.Thestring) {
-		log.Fatalf("cannot use %cg with GOARCH=%s", Thearch.Thechar, p)
+	if !strings.HasPrefix(p, Thearch.LinkArch.Name) {
+		log.Fatalf("cannot use %cg with GOARCH=%s", Thearch.LinkArch.Family, p)
 	}
 	goarch = p
 
-	Ctxt = obj.Linknew(Thearch.Thelinkarch)
+	Ctxt = obj.Linknew(Thearch.LinkArch)
 	Ctxt.DiagFunc = Yyerror
 	Ctxt.Bso = &bstdout
 	bstdout = *obj.Binitw(os.Stdout)
@@ -200,15 +201,13 @@
 	obj.Flagcount("y", "debug declarations in canned imports (with -d)", &Debug['y'])
 	var flag_shared int
 	var flag_dynlink bool
-	switch Thearch.Thechar {
-	case '5', '6', '7', '8', '9':
+	if Thearch.LinkArch.InFamily(sys.ARM, sys.AMD64, sys.ARM64, sys.I386, sys.PPC64) {
 		obj.Flagcount("shared", "generate code that can be linked into a shared library", &flag_shared)
 	}
-	if Thearch.Thechar == '6' {
+	if Thearch.LinkArch.Family == sys.AMD64 {
 		obj.Flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel)
 	}
-	switch Thearch.Thechar {
-	case '5', '6', '7', '8', '9':
+	if Thearch.LinkArch.InFamily(sys.ARM, sys.AMD64, sys.ARM64, sys.I386, sys.PPC64) {
 		flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
 	}
 	obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile)
@@ -301,9 +300,9 @@
 	}
 
 	Thearch.Betypeinit()
-	if Widthptr == 0 {
-		Fatalf("betypeinit failed")
-	}
+	Widthint = Thearch.LinkArch.IntSize
+	Widthptr = Thearch.LinkArch.PtrSize
+	Widthreg = Thearch.LinkArch.RegSize
 
 	initUniverse()
 
diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
index 63f7bf8..bfb65ad 100644
--- a/src/cmd/compile/internal/gc/pgen.go
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -7,6 +7,7 @@
 import (
 	"cmd/compile/internal/ssa"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"crypto/md5"
 	"fmt"
 	"sort"
@@ -286,7 +287,7 @@
 		if haspointers(n.Type) {
 			stkptrsize = Stksize
 		}
-		if Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+		if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) {
 			Stksize = Rnd(Stksize, int64(Widthptr))
 		}
 		if Stksize >= 1<<31 {
@@ -323,7 +324,7 @@
 		Fatalf("bad checknil")
 	}
 
-	if ((Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
+	if (Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
 		var reg Node
 		Regalloc(&reg, Types[Tptr], n)
 		Cgen(n, &reg)
diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go
index 43f594e..6e43d31 100644
--- a/src/cmd/compile/internal/gc/plive.go
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -17,6 +17,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"sort"
 	"strings"
@@ -1396,7 +1397,7 @@
 						// The instruction before a call to deferreturn is always a
 						// no-op, to keep PC-specific data unambiguous.
 						prev := p.Opt.(*obj.Prog)
-						if Ctxt.Arch.Thechar == '9' {
+						if Ctxt.Arch.Family == sys.PPC64 {
 							// On ppc64 there is an additional instruction
 							// (another no-op or reload of toc pointer) before
 							// the call.
diff --git a/src/cmd/compile/internal/gc/reg.go b/src/cmd/compile/internal/gc/reg.go
index 26746a5..8705d6d 100644
--- a/src/cmd/compile/internal/gc/reg.go
+++ b/src/cmd/compile/internal/gc/reg.go
@@ -33,6 +33,7 @@
 import (
 	"bytes"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"sort"
 	"strings"
@@ -249,7 +250,7 @@
 	p1.As = Thearch.Optoas(OAS, Types[uint8(v.etype)])
 
 	// TODO(rsc): Remove special case here.
-	if (Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && v.etype == TBOOL {
+	if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) && v.etype == TBOOL {
 		p1.As = Thearch.Optoas(OAS, Types[TUINT8])
 	}
 	p1.From.Type = obj.TYPE_REG
@@ -302,7 +303,7 @@
 		// TODO(rsc): Remove special case here.
 	case obj.TYPE_ADDR:
 		var bit Bits
-		if Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+		if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) {
 			goto memcase
 		}
 		a.Type = obj.TYPE_MEM
@@ -368,7 +369,7 @@
 				if v.etype == et {
 					if int64(v.width) == w {
 						// TODO(rsc): Remove special case for arm here.
-						if flag == 0 || Thearch.Thechar != '5' {
+						if flag == 0 || Thearch.LinkArch.Family != sys.ARM {
 							return blsh(uint(i))
 						}
 					}
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 127a7c4..90c4d4e 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -13,6 +13,7 @@
 
 	"cmd/compile/internal/ssa"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 )
 
 var ssaEnabled = true
@@ -24,13 +25,13 @@
 	ssaExp.unimplemented = false
 	ssaExp.mustImplement = true
 	if ssaConfig == nil {
-		ssaConfig = ssa.NewConfig(Thearch.Thestring, &ssaExp, Ctxt, Debug['N'] == 0)
+		ssaConfig = ssa.NewConfig(Thearch.LinkArch.Name, &ssaExp, Ctxt, Debug['N'] == 0)
 	}
 	return ssaConfig
 }
 
 func shouldssa(fn *Node) bool {
-	switch Thearch.Thestring {
+	switch Thearch.LinkArch.Name {
 	default:
 		// Only available for testing.
 		if os.Getenv("SSATEST") == "" {
@@ -2409,7 +2410,7 @@
 	// so far has only been noticed for Bswap32 and the 16-bit count
 	// leading/trailing instructions, but heuristics might change
 	// in the future or on different architectures).
-	if !ssaEnabled || ssa.IntrinsicsDisable || Thearch.Thechar != '6' {
+	if !ssaEnabled || ssa.IntrinsicsDisable || Thearch.LinkArch.Family != sys.AMD64 {
 		return false
 	}
 	if s != nil && s.Pkg != nil && s.Pkg.Path == "runtime/internal/sys" {
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index ff8ddea..586a8e9c 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -6,6 +6,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"strings"
 )
@@ -672,8 +673,7 @@
 		walkexprlist(n.List.Slice(), init)
 
 		if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
-			switch Thearch.Thechar {
-			case '5', '6', '7', '9':
+			if Thearch.LinkArch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.PPC64) {
 				n.Op = OSQRT
 				n.Left = n.List.First()
 				n.List.Set(nil)
@@ -1056,7 +1056,7 @@
 		n = walkexpr(n, init)
 
 	case OCONV, OCONVNOP:
-		if Thearch.Thechar == '5' {
+		if Thearch.LinkArch.Family == sys.ARM {
 			if n.Left.Type.IsFloat() {
 				if n.Type.Etype == TINT64 {
 					n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
@@ -3274,7 +3274,7 @@
 // The result of walkrotate MUST be assigned back to n, e.g.
 // 	n.Left = walkrotate(n.Left)
 func walkrotate(n *Node) *Node {
-	if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+	if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) {
 		return n
 	}
 
@@ -3401,7 +3401,7 @@
 	// if >= 0, nr is 1<<pow // 1 if nr is negative.
 
 	// TODO(minux)
-	if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+	if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) {
 		return n
 	}
 
diff --git a/src/cmd/compile/internal/mips64/galign.go b/src/cmd/compile/internal/mips64/galign.go
index 9d582f4..22890c8 100644
--- a/src/cmd/compile/internal/mips64/galign.go
+++ b/src/cmd/compile/internal/mips64/galign.go
@@ -11,18 +11,12 @@
 )
 
 func betypeinit() {
-	gc.Widthptr = 8
-	gc.Widthint = 8
-	gc.Widthreg = 8
 }
 
 func Main() {
-	gc.Thearch.Thechar = '0'
-	gc.Thearch.Thestring = "mips64"
-	gc.Thearch.Thelinkarch = &mips.Linkmips64
+	gc.Thearch.LinkArch = &mips.Linkmips64
 	if obj.Getgoarch() == "mips64le" {
-		gc.Thearch.Thestring = "mips64le"
-		gc.Thearch.Thelinkarch = &mips.Linkmips64le
+		gc.Thearch.LinkArch = &mips.Linkmips64le
 	}
 	gc.Thearch.REGSP = mips.REGSP
 	gc.Thearch.REGCTXT = mips.REGCTXT
diff --git a/src/cmd/compile/internal/ppc64/galign.go b/src/cmd/compile/internal/ppc64/galign.go
index 91bece6..04fa4cf 100644
--- a/src/cmd/compile/internal/ppc64/galign.go
+++ b/src/cmd/compile/internal/ppc64/galign.go
@@ -11,10 +11,6 @@
 )
 
 func betypeinit() {
-	gc.Widthptr = 8
-	gc.Widthint = 8
-	gc.Widthreg = 8
-
 	if gc.Ctxt.Flag_shared != 0 {
 		gc.Thearch.ReservedRegs = append(gc.Thearch.ReservedRegs, ppc64.REG_R2)
 		gc.Thearch.ReservedRegs = append(gc.Thearch.ReservedRegs, ppc64.REG_R12)
@@ -22,12 +18,9 @@
 }
 
 func Main() {
-	gc.Thearch.Thechar = '9'
-	gc.Thearch.Thestring = "ppc64"
-	gc.Thearch.Thelinkarch = &ppc64.Linkppc64
+	gc.Thearch.LinkArch = &ppc64.Linkppc64
 	if obj.Getgoarch() == "ppc64le" {
-		gc.Thearch.Thestring = "ppc64le"
-		gc.Thearch.Thelinkarch = &ppc64.Linkppc64le
+		gc.Thearch.LinkArch = &ppc64.Linkppc64le
 	}
 	gc.Thearch.REGSP = ppc64.REGSP
 	gc.Thearch.REGCTXT = ppc64.REGCTXT
diff --git a/src/cmd/compile/internal/x86/galign.go b/src/cmd/compile/internal/x86/galign.go
index 4ab72b6..738d887 100644
--- a/src/cmd/compile/internal/x86/galign.go
+++ b/src/cmd/compile/internal/x86/galign.go
@@ -13,15 +13,10 @@
 )
 
 func betypeinit() {
-	gc.Widthptr = 4
-	gc.Widthint = 4
-	gc.Widthreg = 4
 }
 
 func Main() {
-	gc.Thearch.Thechar = '8'
-	gc.Thearch.Thestring = "386"
-	gc.Thearch.Thelinkarch = &x86.Link386
+	gc.Thearch.LinkArch = &x86.Link386
 	gc.Thearch.REGSP = x86.REGSP
 	gc.Thearch.REGCTXT = x86.REGCTXT
 	gc.Thearch.REGCALLX = x86.REG_BX
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index df9d9f3..123d5cc 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -46,6 +46,7 @@
 	"internal/obj/ppc64",
 	"internal/obj/s390x",
 	"internal/obj/x86",
+	"internal/sys",
 	"link",
 	"link/internal/amd64",
 	"link/internal/arm",
diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go
index 92ffc7b..042e6ab 100644
--- a/src/cmd/internal/obj/arm/obj5.go
+++ b/src/cmd/internal/obj/arm/obj5.go
@@ -32,7 +32,7 @@
 
 import (
 	"cmd/internal/obj"
-	"encoding/binary"
+	"cmd/internal/sys"
 	"fmt"
 	"log"
 	"math"
@@ -412,7 +412,7 @@
 				p.As = AMOVW
 				p.From.Type = obj.TYPE_MEM
 				p.From.Reg = REGG
-				p.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+				p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
 				p.To.Type = obj.TYPE_REG
 				p.To.Reg = REG_R1
 
@@ -708,9 +708,9 @@
 	p.As = AMOVW
 	p.From.Type = obj.TYPE_MEM
 	p.From.Reg = REGG
-	p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+	p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
 	if ctxt.Cursym.Cfunc {
-		p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+		p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 	}
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_R1
@@ -1032,15 +1032,10 @@
 }
 
 var Linkarm = obj.LinkArch{
-	ByteOrder:  binary.LittleEndian,
-	Name:       "arm",
-	Thechar:    '5',
+	Arch:       sys.ArchARM,
 	Preprocess: preprocess,
 	Assemble:   span5,
 	Follow:     follow,
 	Progedit:   progedit,
 	UnaryDst:   unaryDst,
-	Minlc:      4,
-	Ptrsize:    4,
-	Regsize:    4,
 }
diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go
index b3de44c..d833bee 100644
--- a/src/cmd/internal/obj/arm64/obj7.go
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -32,7 +32,7 @@
 
 import (
 	"cmd/internal/obj"
-	"encoding/binary"
+	"cmd/internal/sys"
 	"fmt"
 	"log"
 	"math"
@@ -56,9 +56,9 @@
 	p.As = AMOVD
 	p.From.Type = obj.TYPE_MEM
 	p.From.Reg = REGG
-	p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+	p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
 	if ctxt.Cursym.Cfunc {
-		p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+		p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 	}
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_R1
@@ -778,7 +778,7 @@
 				q.As = AMOVD
 				q.From.Type = obj.TYPE_MEM
 				q.From.Reg = REGG
-				q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+				q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R1
 
@@ -941,15 +941,10 @@
 }
 
 var Linkarm64 = obj.LinkArch{
-	ByteOrder:  binary.LittleEndian,
-	Name:       "arm64",
-	Thechar:    '7',
+	Arch:       sys.ArchARM64,
 	Preprocess: preprocess,
 	Assemble:   span7,
 	Follow:     follow,
 	Progedit:   progedit,
 	UnaryDst:   unaryDst,
-	Minlc:      4,
-	Ptrsize:    8,
-	Regsize:    8,
 }
diff --git a/src/cmd/internal/obj/data.go b/src/cmd/internal/obj/data.go
index a3cc178..37ab70b 100644
--- a/src/cmd/internal/obj/data.go
+++ b/src/cmd/internal/obj/data.go
@@ -110,7 +110,7 @@
 // WriteAddr writes an address of size siz into s at offset off.
 // rsym and roff specify the relocation for the address.
 func (s *LSym) WriteAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64) {
-	if siz != ctxt.Arch.Ptrsize {
+	if siz != ctxt.Arch.PtrSize {
 		ctxt.Diag("WriteAddr: bad address size: %d", siz)
 	}
 	s.prepwrite(ctxt, off, siz)
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 9c06e8d..81a5689 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -30,7 +30,7 @@
 
 package obj
 
-import "encoding/binary"
+import "cmd/internal/sys"
 
 // An Addr is an argument to an instruction.
 // The general forms and their encodings are:
@@ -682,15 +682,15 @@
 // on the stack in the function prologue and so always have a pointer between
 // the hardware stack pointer and the local variable area.
 func (ctxt *Link) FixedFrameSize() int64 {
-	switch ctxt.Arch.Thechar {
-	case '6', '8':
+	switch ctxt.Arch.Family {
+	case sys.AMD64, sys.I386:
 		return 0
-	case '9':
+	case sys.PPC64:
 		// PIC code on ppc64le requires 32 bytes of stack, and it's easier to
 		// just use that much stack always on ppc64x.
-		return int64(4 * ctxt.Arch.Ptrsize)
+		return int64(4 * ctxt.Arch.PtrSize)
 	default:
-		return int64(ctxt.Arch.Ptrsize)
+		return int64(ctxt.Arch.PtrSize)
 	}
 }
 
@@ -701,17 +701,12 @@
 
 // LinkArch is the definition of a single architecture.
 type LinkArch struct {
-	ByteOrder  binary.ByteOrder
-	Name       string
-	Thechar    int
+	*sys.Arch
 	Preprocess func(*Link, *LSym)
 	Assemble   func(*Link, *LSym)
 	Follow     func(*Link, *LSym)
 	Progedit   func(*Link, *Prog)
 	UnaryDst   map[As]bool // Instruction takes one operand, a destination.
-	Minlc      int
-	Ptrsize    int
-	Regsize    int
 }
 
 /* executable header types */
diff --git a/src/cmd/internal/obj/mips/obj0.go b/src/cmd/internal/obj/mips/obj0.go
index ca7d446..49fc2fb 100644
--- a/src/cmd/internal/obj/mips/obj0.go
+++ b/src/cmd/internal/obj/mips/obj0.go
@@ -31,7 +31,7 @@
 
 import (
 	"cmd/internal/obj"
-	"encoding/binary"
+	"cmd/internal/sys"
 	"fmt"
 	"math"
 )
@@ -336,7 +336,7 @@
 				q.As = AMOVV
 				q.From.Type = obj.TYPE_MEM
 				q.From.Reg = REGG
-				q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+				q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R1
 
@@ -559,9 +559,9 @@
 	p.As = AMOVV
 	p.From.Type = obj.TYPE_MEM
 	p.From.Reg = REGG
-	p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+	p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
 	if ctxt.Cursym.Cfunc {
-		p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+		p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 	}
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_R1
@@ -1469,27 +1469,17 @@
 }
 
 var Linkmips64 = obj.LinkArch{
-	ByteOrder:  binary.BigEndian,
-	Name:       "mips64",
-	Thechar:    '0',
+	Arch:       sys.ArchMIPS64,
 	Preprocess: preprocess,
 	Assemble:   span0,
 	Follow:     follow,
 	Progedit:   progedit,
-	Minlc:      4,
-	Ptrsize:    8,
-	Regsize:    8,
 }
 
 var Linkmips64le = obj.LinkArch{
-	ByteOrder:  binary.LittleEndian,
-	Name:       "mips64le",
-	Thechar:    '0',
+	Arch:       sys.ArchMIPS64LE,
 	Preprocess: preprocess,
 	Assemble:   span0,
 	Follow:     follow,
 	Progedit:   progedit,
-	Minlc:      4,
-	Ptrsize:    8,
-	Regsize:    8,
 }
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index 30a380f..bdd3bfc 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -109,6 +109,7 @@
 
 import (
 	"bufio"
+	"cmd/internal/sys"
 	"fmt"
 	"log"
 	"path/filepath"
@@ -556,7 +557,7 @@
 		} else if r.Type == R_TLS_LE {
 			name = "TLS"
 		}
-		if ctxt.Arch.Thechar == '5' || ctxt.Arch.Thechar == '9' {
+		if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
 			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(int64(r.Add)))
 		} else {
 			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, int64(r.Add))
diff --git a/src/cmd/internal/obj/pcln.go b/src/cmd/internal/obj/pcln.go
index 9770c96..eca7531 100644
--- a/src/cmd/internal/obj/pcln.go
+++ b/src/cmd/internal/obj/pcln.go
@@ -100,7 +100,7 @@
 		}
 
 		if started != 0 {
-			addvarint(ctxt, dst, uint32((p.Pc-pc)/int64(ctxt.Arch.Minlc)))
+			addvarint(ctxt, dst, uint32((p.Pc-pc)/int64(ctxt.Arch.MinLC)))
 			pc = p.Pc
 		}
 
@@ -120,7 +120,7 @@
 		if ctxt.Debugpcln != 0 {
 			fmt.Fprintf(ctxt.Bso, "%6x done\n", uint64(int64(func_.Text.Pc)+func_.Size))
 		}
-		addvarint(ctxt, dst, uint32((func_.Size-pc)/int64(ctxt.Arch.Minlc)))
+		addvarint(ctxt, dst, uint32((func_.Size-pc)/int64(ctxt.Arch.MinLC)))
 		addvarint(ctxt, dst, 0) // terminator
 	}
 
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index 483df3a..7a24d1d 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -31,7 +31,7 @@
 
 import (
 	"cmd/internal/obj"
-	"encoding/binary"
+	"cmd/internal/sys"
 	"fmt"
 	"math"
 )
@@ -592,7 +592,7 @@
 				q.As = AMOVD
 				q.From.Type = obj.TYPE_MEM
 				q.From.Reg = REGG
-				q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+				q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R3
 
@@ -827,9 +827,9 @@
 	p.As = AMOVD
 	p.From.Type = obj.TYPE_MEM
 	p.From.Reg = REGG
-	p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+	p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
 	if ctxt.Cursym.Cfunc {
-		p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+		p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 	}
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_R3
@@ -1181,27 +1181,17 @@
 }
 
 var Linkppc64 = obj.LinkArch{
-	ByteOrder:  binary.BigEndian,
-	Name:       "ppc64",
-	Thechar:    '9',
+	Arch:       sys.ArchPPC64,
 	Preprocess: preprocess,
 	Assemble:   span9,
 	Follow:     follow,
 	Progedit:   progedit,
-	Minlc:      4,
-	Ptrsize:    8,
-	Regsize:    8,
 }
 
 var Linkppc64le = obj.LinkArch{
-	ByteOrder:  binary.LittleEndian,
-	Name:       "ppc64le",
-	Thechar:    '9',
+	Arch:       sys.ArchPPC64LE,
 	Preprocess: preprocess,
 	Assemble:   span9,
 	Follow:     follow,
 	Progedit:   progedit,
-	Minlc:      4,
-	Ptrsize:    8,
-	Regsize:    8,
 }
diff --git a/src/cmd/internal/obj/s390x/objz.go b/src/cmd/internal/obj/s390x/objz.go
index 239deec..454a0d7 100644
--- a/src/cmd/internal/obj/s390x/objz.go
+++ b/src/cmd/internal/obj/s390x/objz.go
@@ -31,7 +31,7 @@
 
 import (
 	"cmd/internal/obj"
-	"encoding/binary"
+	"cmd/internal/sys"
 	"fmt"
 	"math"
 )
@@ -460,7 +460,7 @@
 				q.As = AMOVD
 				q.From.Type = obj.TYPE_MEM
 				q.From.Reg = REGG
-				q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+				q.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
 				q.To.Type = obj.TYPE_REG
 				q.To.Reg = REG_R3
 
@@ -664,9 +664,9 @@
 	p.As = AMOVD
 	p.From.Type = obj.TYPE_MEM
 	p.From.Reg = REGG
-	p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+	p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
 	if ctxt.Cursym.Cfunc {
-		p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+		p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 	}
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_R3
@@ -999,15 +999,10 @@
 }
 
 var Links390x = obj.LinkArch{
-	ByteOrder:  binary.BigEndian,
-	Name:       "s390x",
-	Thechar:    'z',
+	Arch:       sys.ArchS390X,
 	Preprocess: preprocess,
 	Assemble:   spanz,
 	Follow:     follow,
 	Progedit:   progedit,
 	UnaryDst:   unaryDst,
-	Minlc:      2,
-	Ptrsize:    8,
-	Regsize:    8,
 }
diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go
index 64df62a..beacc94 100644
--- a/src/cmd/internal/obj/sym.go
+++ b/src/cmd/internal/obj/sym.go
@@ -32,6 +32,7 @@
 package obj
 
 import (
+	"cmd/internal/sys"
 	"log"
 	"os"
 	"path/filepath"
@@ -100,7 +101,7 @@
 	}
 
 	// On arm, record goarm.
-	if ctxt.Arch.Thechar == '5' {
+	if ctxt.Arch.Family == sys.ARM {
 		ctxt.Goarm = Getgoarm()
 	}
 
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index 773494b..b940094 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -1754,7 +1754,7 @@
 }
 
 func spadjop(ctxt *obj.Link, p *obj.Prog, l, q obj.As) obj.As {
-	if p.Mode != 64 || ctxt.Arch.Ptrsize == 4 {
+	if p.Mode != 64 || ctxt.Arch.PtrSize == 4 {
 		return l
 	}
 	return q
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index 0e8aeca..302a597 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -32,7 +32,7 @@
 
 import (
 	"cmd/internal/obj"
-	"encoding/binary"
+	"cmd/internal/sys"
 	"fmt"
 	"log"
 	"math"
@@ -49,7 +49,7 @@
 		return true
 	}
 
-	if ctxt.Arch.Regsize == 4 {
+	if ctxt.Arch.RegSize == 4 {
 		switch ctxt.Headtype {
 		case obj.Hlinux,
 			obj.Hnacl,
@@ -75,7 +75,7 @@
 func progedit(ctxt *obj.Link, p *obj.Prog) {
 	// Maintain information about code generation mode.
 	if ctxt.Mode == 0 {
-		ctxt.Mode = ctxt.Arch.Regsize * 8
+		ctxt.Mode = ctxt.Arch.RegSize * 8
 	}
 	p.Mode = int8(ctxt.Mode)
 
@@ -207,7 +207,7 @@
 	}
 
 	// Rewrite MOVL/MOVQ $XXX(FP/SP) as LEAL/LEAQ.
-	if p.From.Type == obj.TYPE_ADDR && (ctxt.Arch.Thechar == '6' || p.From.Name != obj.NAME_EXTERN && p.From.Name != obj.NAME_STATIC) {
+	if p.From.Type == obj.TYPE_ADDR && (ctxt.Arch.Family == sys.AMD64 || p.From.Name != obj.NAME_EXTERN && p.From.Name != obj.NAME_STATIC) {
 		switch p.As {
 		case AMOVL:
 			p.As = ALEAL
@@ -614,7 +614,7 @@
 		// Make room for to save a base pointer. If autoffset == 0,
 		// this might do something special like a tail jump to
 		// another function, so in that case we omit this.
-		bpsize = ctxt.Arch.Ptrsize
+		bpsize = ctxt.Arch.PtrSize
 
 		autoffset += int32(bpsize)
 		p.To.Offset += int64(bpsize)
@@ -656,7 +656,7 @@
 	}
 
 	if autoffset != 0 {
-		if autoffset%int32(ctxt.Arch.Regsize) != 0 {
+		if autoffset%int32(ctxt.Arch.RegSize) != 0 {
 			ctxt.Diag("unaligned stack size %d", autoffset)
 		}
 		p = obj.Appendp(ctxt, p)
@@ -671,10 +671,10 @@
 		p = obj.Appendp(ctxt, p)
 
 		p.As = obj.ANOP
-		p.Spadj = int32(-ctxt.Arch.Ptrsize)
+		p.Spadj = int32(-ctxt.Arch.PtrSize)
 		p = obj.Appendp(ctxt, p)
 		p.As = obj.ANOP
-		p.Spadj = int32(ctxt.Arch.Ptrsize)
+		p.Spadj = int32(ctxt.Arch.PtrSize)
 	}
 
 	deltasp := autoffset
@@ -724,7 +724,7 @@
 		p.As = AMOVQ
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = REG_CX
-		p.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+		p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_BX
 		if ctxt.Headtype == obj.Hnacl && p.Mode == 64 {
@@ -757,7 +757,7 @@
 		p.As = ALEAQ
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = REG_SP
-		p.From.Offset = int64(autoffset) + int64(ctxt.Arch.Regsize)
+		p.From.Offset = int64(autoffset) + int64(ctxt.Arch.RegSize)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_DI
 		if ctxt.Headtype == obj.Hnacl || p.Mode == 32 {
@@ -935,7 +935,7 @@
 // Returns last new instruction.
 func load_g_cx(ctxt *obj.Link, p *obj.Prog) *obj.Prog {
 	p.As = AMOVQ
-	if ctxt.Arch.Ptrsize == 4 {
+	if ctxt.Arch.PtrSize == 4 {
 		p.As = AMOVL
 	}
 	p.From.Type = obj.TYPE_MEM
@@ -984,9 +984,9 @@
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_SP
 		indir_cx(ctxt, p, &p.To)
-		p.To.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+		p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
 		if ctxt.Cursym.Cfunc {
-			p.To.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+			p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 		}
 	} else if framesize <= obj.StackBig {
 		// large stack: SP-framesize <= stackguard-StackSmall
@@ -1006,9 +1006,9 @@
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_AX
 		indir_cx(ctxt, p, &p.To)
-		p.To.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+		p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
 		if ctxt.Cursym.Cfunc {
-			p.To.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+			p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 		}
 	} else {
 		// Such a large stack we need to protect against wraparound.
@@ -1030,9 +1030,9 @@
 
 		p.As = mov
 		indir_cx(ctxt, p, &p.From)
-		p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+		p.From.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
 		if ctxt.Cursym.Cfunc {
-			p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+			p.From.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
 		}
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_SI
@@ -1402,43 +1402,28 @@
 }
 
 var Linkamd64 = obj.LinkArch{
-	ByteOrder:  binary.LittleEndian,
-	Name:       "amd64",
-	Thechar:    '6',
+	Arch:       sys.ArchAMD64,
 	Preprocess: preprocess,
 	Assemble:   span6,
 	Follow:     follow,
 	Progedit:   progedit,
 	UnaryDst:   unaryDst,
-	Minlc:      1,
-	Ptrsize:    8,
-	Regsize:    8,
 }
 
 var Linkamd64p32 = obj.LinkArch{
-	ByteOrder:  binary.LittleEndian,
-	Name:       "amd64p32",
-	Thechar:    '6',
+	Arch:       sys.ArchAMD64P32,
 	Preprocess: preprocess,
 	Assemble:   span6,
 	Follow:     follow,
 	Progedit:   progedit,
 	UnaryDst:   unaryDst,
-	Minlc:      1,
-	Ptrsize:    4,
-	Regsize:    8,
 }
 
 var Link386 = obj.LinkArch{
-	ByteOrder:  binary.LittleEndian,
-	Name:       "386",
-	Thechar:    '8',
+	Arch:       sys.Arch386,
 	Preprocess: preprocess,
 	Assemble:   span6,
 	Follow:     follow,
 	Progedit:   progedit,
 	UnaryDst:   unaryDst,
-	Minlc:      1,
-	Ptrsize:    4,
-	Regsize:    4,
 }
diff --git a/src/cmd/internal/sys/arch.go b/src/cmd/internal/sys/arch.go
new file mode 100644
index 0000000..0a7423a
--- /dev/null
+++ b/src/cmd/internal/sys/arch.go
@@ -0,0 +1,145 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sys
+
+import "encoding/binary"
+
+// ArchFamily represents an architecture family.
+type ArchFamily byte
+
+const (
+	AMD64  ArchFamily = '6'
+	ARM    ArchFamily = '5'
+	ARM64  ArchFamily = '7'
+	I386   ArchFamily = '8'
+	MIPS64 ArchFamily = '0'
+	PPC64  ArchFamily = '9'
+	S390X  ArchFamily = 'z'
+)
+
+// Arch represents an individual architecture.
+type Arch struct {
+	Name   string
+	Family ArchFamily
+
+	ByteOrder binary.ByteOrder
+
+	IntSize int
+	PtrSize int
+	RegSize int
+
+	MinLC int
+}
+
+// HasFamily reports whether a is a member of any of the specified
+// architecture families.
+func (a *Arch) InFamily(xs ...ArchFamily) bool {
+	for _, x := range xs {
+		if a.Family == x {
+			return true
+		}
+	}
+	return false
+}
+
+var Arch386 = &Arch{
+	Name:      "386",
+	Family:    I386,
+	ByteOrder: binary.LittleEndian,
+	IntSize:   4,
+	PtrSize:   4,
+	RegSize:   4,
+	MinLC:     1,
+}
+
+var ArchAMD64 = &Arch{
+	Name:      "amd64",
+	Family:    AMD64,
+	ByteOrder: binary.LittleEndian,
+	IntSize:   8,
+	PtrSize:   8,
+	RegSize:   8,
+	MinLC:     1,
+}
+
+var ArchAMD64P32 = &Arch{
+	Name:      "amd64p32",
+	Family:    AMD64,
+	ByteOrder: binary.LittleEndian,
+	IntSize:   4,
+	PtrSize:   4,
+	RegSize:   8,
+	MinLC:     1,
+}
+
+var ArchARM = &Arch{
+	Name:      "arm",
+	Family:    ARM,
+	ByteOrder: binary.LittleEndian,
+	IntSize:   4,
+	PtrSize:   4,
+	RegSize:   4,
+	MinLC:     4,
+}
+
+var ArchARM64 = &Arch{
+	Name:      "arm64",
+	Family:    ARM64,
+	ByteOrder: binary.LittleEndian,
+	IntSize:   8,
+	PtrSize:   8,
+	RegSize:   8,
+	MinLC:     4,
+}
+
+var ArchMIPS64 = &Arch{
+	Name:      "mips64",
+	Family:    MIPS64,
+	ByteOrder: binary.BigEndian,
+	IntSize:   8,
+	PtrSize:   8,
+	RegSize:   8,
+	MinLC:     4,
+}
+
+var ArchMIPS64LE = &Arch{
+	Name:      "mips64le",
+	Family:    MIPS64,
+	ByteOrder: binary.LittleEndian,
+	IntSize:   8,
+	PtrSize:   8,
+	RegSize:   8,
+	MinLC:     4,
+}
+
+var ArchPPC64 = &Arch{
+	Name:      "ppc64",
+	Family:    PPC64,
+	ByteOrder: binary.BigEndian,
+	IntSize:   8,
+	PtrSize:   8,
+	RegSize:   8,
+	MinLC:     4,
+}
+
+var ArchPPC64LE = &Arch{
+	Name:      "ppc64le",
+	Family:    PPC64,
+	ByteOrder: binary.LittleEndian,
+	IntSize:   8,
+	PtrSize:   8,
+	RegSize:   8,
+	MinLC:     4,
+}
+
+var ArchS390X = &Arch{
+	Name:      "s390x",
+	Family:    S390X,
+	ByteOrder: binary.BigEndian,
+	IntSize:   8,
+	PtrSize:   8,
+	RegSize:   8,
+	MinLC:     2,
+}
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
index 25232e6..2b219da 100644
--- a/src/cmd/link/internal/amd64/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -285,7 +285,7 @@
 			return
 		}
 
-		if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.Thearch.Ptrsize) && r.Off == 0 {
+		if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.SysArch.PtrSize) && r.Off == 0 {
 			// Mach-O relocations are a royal pain to lay out.
 			// They use a compact stateful bytecode representation
 			// that is too much bother to deal with.
diff --git a/src/cmd/link/internal/amd64/l.go b/src/cmd/link/internal/amd64/l.go
index 4ec8610..2fbc8ad 100644
--- a/src/cmd/link/internal/amd64/l.go
+++ b/src/cmd/link/internal/amd64/l.go
@@ -31,16 +31,11 @@
 package amd64
 
 const (
-	thechar   = '6'
 	MaxAlign  = 32 // max data alignment
 	MinAlign  = 1  // min data alignment
 	FuncAlign = 16
 )
 
-const (
-	MINLC = 1
-)
-
 /* Used by ../internal/ld/dwarf.go */
 const (
 	DWARFREGSP = 7
diff --git a/src/cmd/link/internal/amd64/obj.go b/src/cmd/link/internal/amd64/obj.go
index f9e13f2..860f588 100644
--- a/src/cmd/link/internal/amd64/obj.go
+++ b/src/cmd/link/internal/amd64/obj.go
@@ -32,6 +32,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
 	"log"
@@ -45,20 +46,14 @@
 }
 
 func linkarchinit() {
-	ld.Thestring = "amd64"
-	ld.Thelinkarch = &ld.Linkamd64
+	ld.SysArch = sys.ArchAMD64
 	if obj.Getgoarch() == "amd64p32" {
-		ld.Thelinkarch = &ld.Linkamd64p32
+		ld.SysArch = sys.ArchAMD64P32
 	}
 
-	ld.Thearch.Thechar = thechar
-	ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
-	ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
-	ld.Thearch.Regsize = ld.Thelinkarch.Regsize
 	ld.Thearch.Funcalign = FuncAlign
 	ld.Thearch.Maxalign = MaxAlign
 	ld.Thearch.Minalign = MinAlign
-	ld.Thearch.Minlc = MINLC
 	ld.Thearch.Dwarfregsp = DWARFREGSP
 	ld.Thearch.Dwarfreglr = DWARFREGLR
 
diff --git a/src/cmd/link/internal/arm/l.go b/src/cmd/link/internal/arm/l.go
index 58aecc4..2b73a7b 100644
--- a/src/cmd/link/internal/arm/l.go
+++ b/src/cmd/link/internal/arm/l.go
@@ -63,11 +63,9 @@
 // THE SOFTWARE.
 
 const (
-	thechar   = '5'
 	MaxAlign  = 8 // max data alignment
 	MinAlign  = 1 // min data alignment
 	FuncAlign = 4 // single-instruction alignment
-	MINLC     = 4
 )
 
 /* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/arm/obj.go b/src/cmd/link/internal/arm/obj.go
index bcd61fd..9125a1f 100644
--- a/src/cmd/link/internal/arm/obj.go
+++ b/src/cmd/link/internal/arm/obj.go
@@ -32,6 +32,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
 	"log"
@@ -45,17 +46,11 @@
 }
 
 func linkarchinit() {
-	ld.Thestring = "arm"
-	ld.Thelinkarch = &ld.Linkarm
+	ld.SysArch = sys.ArchARM
 
-	ld.Thearch.Thechar = thechar
-	ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
-	ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
-	ld.Thearch.Regsize = ld.Thelinkarch.Regsize
 	ld.Thearch.Funcalign = FuncAlign
 	ld.Thearch.Maxalign = MaxAlign
 	ld.Thearch.Minalign = MinAlign
-	ld.Thearch.Minlc = MINLC
 	ld.Thearch.Dwarfregsp = DWARFREGSP
 	ld.Thearch.Dwarfreglr = DWARFREGLR
 
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index 8227dc0..fd28e86 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -375,7 +375,7 @@
 		}
 		// The TCB is two pointers. This is not documented anywhere, but is
 		// de facto part of the ABI.
-		v := r.Sym.Value + int64(2*ld.Thearch.Ptrsize)
+		v := r.Sym.Value + int64(2*ld.SysArch.PtrSize)
 		if v < 0 || v >= 32678 {
 			ld.Diag("TLS offset out of range %d", v)
 		}
diff --git a/src/cmd/link/internal/arm64/l.go b/src/cmd/link/internal/arm64/l.go
index b9b7ea5..67ad5c9 100644
--- a/src/cmd/link/internal/arm64/l.go
+++ b/src/cmd/link/internal/arm64/l.go
@@ -62,11 +62,9 @@
 // THE SOFTWARE.
 
 const (
-	thechar   = '7'
 	MaxAlign  = 32 // max data alignment
 	MinAlign  = 1  // min data alignment
 	FuncAlign = 8
-	MINLC     = 4
 )
 
 /* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go
index 693e106..1169e79 100644
--- a/src/cmd/link/internal/arm64/obj.go
+++ b/src/cmd/link/internal/arm64/obj.go
@@ -32,6 +32,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
 	"log"
@@ -45,17 +46,11 @@
 }
 
 func linkarchinit() {
-	ld.Thestring = obj.Getgoarch()
-	ld.Thelinkarch = &ld.Linkarm64
+	ld.SysArch = sys.ArchARM64
 
-	ld.Thearch.Thechar = thechar
-	ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
-	ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
-	ld.Thearch.Regsize = ld.Thelinkarch.Regsize
 	ld.Thearch.Funcalign = FuncAlign
 	ld.Thearch.Maxalign = MaxAlign
 	ld.Thearch.Minalign = MinAlign
-	ld.Thearch.Minlc = MINLC
 	ld.Thearch.Dwarfregsp = DWARFREGSP
 	ld.Thearch.Dwarfreglr = DWARFREGLR
 
diff --git a/src/cmd/link/internal/ld/arch.go b/src/cmd/link/internal/ld/arch.go
deleted file mode 100644
index d28f37f..0000000
--- a/src/cmd/link/internal/ld/arch.go
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ld
-
-import "encoding/binary"
-
-var Linkarm = LinkArch{
-	ByteOrder: binary.LittleEndian,
-	Name:      "arm",
-	Thechar:   '5',
-	Minlc:     4,
-	Ptrsize:   4,
-	Regsize:   4,
-}
-
-var Linkarm64 = LinkArch{
-	ByteOrder: binary.LittleEndian,
-	Name:      "arm64",
-	Thechar:   '7',
-	Minlc:     4,
-	Ptrsize:   8,
-	Regsize:   8,
-}
-
-var Linkamd64 = LinkArch{
-	ByteOrder: binary.LittleEndian,
-	Name:      "amd64",
-	Thechar:   '6',
-	Minlc:     1,
-	Ptrsize:   8,
-	Regsize:   8,
-}
-
-var Linkamd64p32 = LinkArch{
-	ByteOrder: binary.LittleEndian,
-	Name:      "amd64p32",
-	Thechar:   '6',
-	Minlc:     1,
-	Ptrsize:   4,
-	Regsize:   8,
-}
-
-var Link386 = LinkArch{
-	ByteOrder: binary.LittleEndian,
-	Name:      "386",
-	Thechar:   '8',
-	Minlc:     1,
-	Ptrsize:   4,
-	Regsize:   4,
-}
-
-var Linkppc64 = LinkArch{
-	ByteOrder: binary.BigEndian,
-	Name:      "ppc64",
-	Thechar:   '9',
-	Minlc:     4,
-	Ptrsize:   8,
-	Regsize:   8,
-}
-
-var Linkppc64le = LinkArch{
-	ByteOrder: binary.LittleEndian,
-	Name:      "ppc64le",
-	Thechar:   '9',
-	Minlc:     4,
-	Ptrsize:   8,
-	Regsize:   8,
-}
-
-var Linkmips64 = LinkArch{
-	ByteOrder: binary.BigEndian,
-	Name:      "mips64",
-	Thechar:   '0',
-	Minlc:     4,
-	Ptrsize:   8,
-	Regsize:   8,
-}
-
-var Linkmips64le = LinkArch{
-	ByteOrder: binary.LittleEndian,
-	Name:      "mips64le",
-	Thechar:   '0',
-	Minlc:     4,
-	Ptrsize:   8,
-	Regsize:   8,
-}
-
-var Links390x = LinkArch{
-	ByteOrder: binary.BigEndian,
-	Name:      "s390x",
-	Thechar:   'z',
-	Minlc:     2,
-	Ptrsize:   8,
-	Regsize:   8,
-}
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index 6bbd6c7..ae430b4 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -34,6 +34,7 @@
 import (
 	"cmd/internal/gcprog"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"log"
 	"os"
@@ -121,7 +122,7 @@
 }
 
 func adduint(ctxt *Link, s *LSym, v uint64) int64 {
-	return adduintxx(ctxt, s, v, Thearch.Intsize)
+	return adduintxx(ctxt, s, v, SysArch.IntSize)
 }
 
 func setuint8(ctxt *Link, s *LSym, r int64, v uint8) int64 {
@@ -138,12 +139,12 @@
 	}
 	s.Attr |= AttrReachable
 	i := s.Size
-	s.Size += int64(ctxt.Arch.Ptrsize)
+	s.Size += int64(ctxt.Arch.PtrSize)
 	Symgrow(ctxt, s, s.Size)
 	r := Addrel(s)
 	r.Sym = t
 	r.Off = int32(i)
-	r.Siz = uint8(ctxt.Arch.Ptrsize)
+	r.Siz = uint8(ctxt.Arch.PtrSize)
 	r.Type = obj.R_ADDR
 	r.Add = add
 	return i + int64(r.Siz)
@@ -163,7 +164,7 @@
 	r.Add = add
 	r.Type = obj.R_PCREL
 	r.Siz = 4
-	if Thearch.Thechar == 'z' {
+	if SysArch.Family == sys.S390X {
 		r.Variant = RV_390_DBL
 	}
 	return i + int64(r.Siz)
@@ -178,15 +179,15 @@
 		s.Type = obj.SDATA
 	}
 	s.Attr |= AttrReachable
-	if off+int64(ctxt.Arch.Ptrsize) > s.Size {
-		s.Size = off + int64(ctxt.Arch.Ptrsize)
+	if off+int64(ctxt.Arch.PtrSize) > s.Size {
+		s.Size = off + int64(ctxt.Arch.PtrSize)
 		Symgrow(ctxt, s, s.Size)
 	}
 
 	r := Addrel(s)
 	r.Sym = t
 	r.Off = int32(off)
-	r.Siz = uint8(ctxt.Arch.Ptrsize)
+	r.Siz = uint8(ctxt.Arch.PtrSize)
 	r.Type = obj.R_ADDR
 	r.Add = add
 	return off + int64(r.Siz)
@@ -202,12 +203,12 @@
 	}
 	s.Attr |= AttrReachable
 	i := s.Size
-	s.Size += int64(ctxt.Arch.Ptrsize)
+	s.Size += int64(ctxt.Arch.PtrSize)
 	Symgrow(ctxt, s, s.Size)
 	r := Addrel(s)
 	r.Sym = t
 	r.Off = int32(i)
-	r.Siz = uint8(ctxt.Arch.Ptrsize)
+	r.Siz = uint8(ctxt.Arch.PtrSize)
 	r.Type = obj.R_SIZE
 	return i + int64(r.Siz)
 }
@@ -356,7 +357,7 @@
 		// We need to be able to reference dynimport symbols when linking against
 		// shared libraries, and Solaris needs it always
 		if HEADTYPE != obj.Hsolaris && r.Sym != nil && r.Sym.Type == obj.SDYNIMPORT && !DynlinkingGo() {
-			if !(Thearch.Thechar == '9' && Linkmode == LinkExternal && r.Sym.Name == ".TOC.") {
+			if !(SysArch.Family == sys.PPC64 && Linkmode == LinkExternal && r.Sym.Name == ".TOC.") {
 				Diag("unhandled relocation for %s (type %d rtype %d)", r.Sym.Name, r.Sym.Type, r.Type)
 			}
 		}
@@ -365,7 +366,7 @@
 		}
 
 		// TODO(mundaym): remove this special case - see issue 14218.
-		if Thearch.Thechar == 'z' {
+		if SysArch.Family == sys.S390X {
 			switch r.Type {
 			case obj.R_PCRELDBL:
 				r.Type = obj.R_PCREL
@@ -394,7 +395,7 @@
 			}
 
 		case obj.R_TLS_LE:
-			isAndroidX86 := goos == "android" && (Thearch.Thechar == '6' || Thearch.Thechar == '8')
+			isAndroidX86 := goos == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
 
 			if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 {
 				r.Done = 0
@@ -404,13 +405,13 @@
 				r.Xsym = r.Sym
 				r.Xadd = r.Add
 				o = 0
-				if Thearch.Thechar != '6' {
+				if SysArch.Family != sys.AMD64 {
 					o = r.Add
 				}
 				break
 			}
 
-			if Iself && Thearch.Thechar == '5' {
+			if Iself && SysArch.Family == sys.ARM {
 				// On ELF ARM, the thread pointer is 8 bytes before
 				// the start of the thread-local data block, so add 8
 				// to the actual TLS offset (r->sym->value).
@@ -428,7 +429,7 @@
 			}
 
 		case obj.R_TLS_IE:
-			isAndroidX86 := goos == "android" && (Thearch.Thechar == '6' || Thearch.Thechar == '8')
+			isAndroidX86 := goos == "android" && (SysArch.InFamily(sys.AMD64, sys.I386))
 
 			if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 {
 				r.Done = 0
@@ -438,7 +439,7 @@
 				r.Xsym = r.Sym
 				r.Xadd = r.Add
 				o = 0
-				if Thearch.Thechar != '6' {
+				if SysArch.Family != sys.AMD64 {
 					o = r.Add
 				}
 				break
@@ -465,7 +466,7 @@
 
 				o = r.Xadd
 				if Iself {
-					if Thearch.Thechar == '6' {
+					if SysArch.Family == sys.AMD64 {
 						o = 0
 					}
 				} else if HEADTYPE == obj.Hdarwin {
@@ -475,10 +476,10 @@
 					// The workaround is that on arm64 don't ever add symaddr to o and always use
 					// extern relocation by requiring rs->dynid >= 0.
 					if rs.Type != obj.SHOSTOBJ {
-						if Thearch.Thechar == '7' && rs.Dynid < 0 {
+						if SysArch.Family == sys.ARM64 && rs.Dynid < 0 {
 							Diag("R_ADDR reloc to %s+%d is not supported on darwin/arm64", rs.Name, o)
 						}
-						if Thearch.Thechar != '7' {
+						if SysArch.Family != sys.ARM64 {
 							o += Symaddr(rs)
 						}
 					}
@@ -498,7 +499,7 @@
 			// fail at runtime. See https://golang.org/issue/7980.
 			// Instead of special casing only amd64, we treat this as an error on all
 			// 64-bit architectures so as to be future-proof.
-			if int32(o) < 0 && Thearch.Ptrsize > 4 && siz == 4 {
+			if int32(o) < 0 && SysArch.PtrSize > 4 && siz == 4 {
 				Diag("non-pc-relative relocation address is too big: %#x (%#x + %#x)", uint64(o), Symaddr(r.Sym), r.Add)
 				errorexit()
 			}
@@ -515,7 +516,7 @@
 				r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
 				o = r.Xadd
 				rs = r.Xsym
-				if Iself && Thearch.Thechar == '6' {
+				if Iself && SysArch.Family == sys.AMD64 {
 					o = 0
 				}
 				break
@@ -544,7 +545,7 @@
 
 				o = r.Xadd
 				if Iself {
-					if Thearch.Thechar == '6' {
+					if SysArch.Family == sys.AMD64 {
 						o = 0
 					}
 				} else if HEADTYPE == obj.Hdarwin {
@@ -556,7 +557,7 @@
 					} else {
 						o += int64(r.Siz)
 					}
-				} else if HEADTYPE == obj.Hwindows && Thearch.Thechar == '6' { // only amd64 needs PCREL
+				} else if HEADTYPE == obj.Hwindows && SysArch.Family == sys.AMD64 { // only amd64 needs PCREL
 					// PE/COFF's PC32 relocation uses the address after the relocated
 					// bytes as the base. Compensate by skewing the addend.
 					o += int64(r.Siz)
@@ -675,7 +676,7 @@
 				r.Add = int64(targ.Plt)
 
 				// jmp *addr
-				if Thearch.Thechar == '8' {
+				if SysArch.Family == sys.I386 {
 					Adduint8(Ctxt, rel, 0xff)
 					Adduint8(Ctxt, rel, 0x25)
 					Addaddr(Ctxt, rel, targ)
@@ -982,7 +983,7 @@
 	s.Attr |= AttrDuplicateOK
 	reachable := s.Attr.Reachable()
 	Addaddr(Ctxt, s, sp)
-	adduintxx(Ctxt, s, uint64(len(value)), Thearch.Ptrsize)
+	adduintxx(Ctxt, s, uint64(len(value)), SysArch.PtrSize)
 
 	// addstring, addaddr, etc., mark the symbols as reachable.
 	// In this case that is not necessarily true, so stick to what
@@ -1128,7 +1129,7 @@
 }
 
 func (p *GCProg) End(size int64) {
-	p.w.ZeroUntil(size / int64(Thearch.Ptrsize))
+	p.w.ZeroUntil(size / int64(SysArch.PtrSize))
 	p.w.End()
 	if debugGCProg {
 		fmt.Fprintf(os.Stderr, "ld: end GCProg\n")
@@ -1144,7 +1145,7 @@
 		return
 	}
 
-	ptrsize := int64(Thearch.Ptrsize)
+	ptrsize := int64(SysArch.PtrSize)
 	nptr := decodetype_ptrdata(typ) / ptrsize
 
 	if debugGCProg {
@@ -1532,7 +1533,7 @@
 	if s != nil && s.Type == obj.STLSBSS {
 		if Iself && (Linkmode == LinkExternal || Debug['d'] == 0) && HEADTYPE != obj.Hopenbsd {
 			sect = addsection(&Segdata, ".tbss", 06)
-			sect.Align = int32(Thearch.Ptrsize)
+			sect.Align = int32(SysArch.PtrSize)
 			sect.Vaddr = 0
 		} else {
 			sect = nil
diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go
index 56c4370..b17b960 100644
--- a/src/cmd/link/internal/ld/deadcode.go
+++ b/src/cmd/link/internal/ld/deadcode.go
@@ -6,6 +6,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"strings"
 	"unicode"
@@ -227,7 +228,7 @@
 func (d *deadcodepass) init() {
 	var names []string
 
-	if Thearch.Thechar == '5' {
+	if SysArch.Family == sys.ARM {
 		// mark some functions that are only referenced after linker code editing
 		if d.ctxt.Goarm == 5 {
 			names = append(names, "_sfloat")
diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go
index 0a6bf09..bc29938 100644
--- a/src/cmd/link/internal/ld/decodesym.go
+++ b/src/cmd/link/internal/ld/decodesym.go
@@ -7,6 +7,7 @@
 import (
 	"bytes"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"debug/elf"
 	"fmt"
 )
@@ -46,39 +47,39 @@
 	}
 }
 
-func commonsize() int      { return 6*Thearch.Ptrsize + 8 }                 // runtime._type
-func structfieldSize() int { return 3 * Thearch.Ptrsize }                   // runtime.structfield
-func uncommonSize() int    { return 2*Thearch.Ptrsize + 2*Thearch.Intsize } // runtime.uncommontype
+func commonsize() int      { return 6*SysArch.PtrSize + 8 }                 // runtime._type
+func structfieldSize() int { return 3 * SysArch.PtrSize }                   // runtime.structfield
+func uncommonSize() int    { return 2*SysArch.PtrSize + 2*SysArch.IntSize } // runtime.uncommontype
 
 // Type.commonType.kind
 func decodetype_kind(s *LSym) uint8 {
-	return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindMask) //  0x13 / 0x1f
+	return uint8(s.P[2*SysArch.PtrSize+7] & obj.KindMask) //  0x13 / 0x1f
 }
 
 // Type.commonType.kind
 func decodetype_noptr(s *LSym) uint8 {
-	return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindNoPointers) //  0x13 / 0x1f
+	return uint8(s.P[2*SysArch.PtrSize+7] & obj.KindNoPointers) //  0x13 / 0x1f
 }
 
 // Type.commonType.kind
 func decodetype_usegcprog(s *LSym) uint8 {
-	return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindGCProg) //  0x13 / 0x1f
+	return uint8(s.P[2*SysArch.PtrSize+7] & obj.KindGCProg) //  0x13 / 0x1f
 }
 
 // Type.commonType.size
 func decodetype_size(s *LSym) int64 {
-	return int64(decode_inuxi(s.P, Thearch.Ptrsize)) // 0x8 / 0x10
+	return int64(decode_inuxi(s.P, SysArch.PtrSize)) // 0x8 / 0x10
 }
 
 // Type.commonType.ptrdata
 func decodetype_ptrdata(s *LSym) int64 {
-	return int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Ptrsize)) // 0x8 / 0x10
+	return int64(decode_inuxi(s.P[SysArch.PtrSize:], SysArch.PtrSize)) // 0x8 / 0x10
 }
 
 // Type.commonType.tflag
 func decodetype_hasUncommon(s *LSym) bool {
 	const tflagUncommon = 1 // see ../../../../reflect/type.go:/^type.tflag
-	return s.P[2*Thearch.Ptrsize+4]&tflagUncommon != 0
+	return s.P[2*SysArch.PtrSize+4]&tflagUncommon != 0
 }
 
 // Find the elf.Section of a given shared library that contains a given address.
@@ -112,11 +113,11 @@
 		Exitf("cannot find gcprog for %s", s.Name)
 		return nil
 	}
-	return decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize)).P
+	return decode_reloc_sym(s, 2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize)).P
 }
 
 func decodetype_gcprog_shlib(s *LSym) uint64 {
-	if Thearch.Thechar == '7' {
+	if SysArch.Family == sys.ARM64 {
 		for _, shlib := range Ctxt.Shlibs {
 			if shlib.Path == s.File {
 				return shlib.gcdata_addresses[s]
@@ -124,7 +125,7 @@
 		}
 		return 0
 	}
-	return decode_inuxi(s.P[2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize):], Thearch.Ptrsize)
+	return decode_inuxi(s.P[2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize):], SysArch.PtrSize)
 }
 
 func decodetype_gcmask(s *LSym) []byte {
@@ -133,14 +134,14 @@
 		ptrdata := decodetype_ptrdata(s)
 		sect := findShlibSection(s.File, addr)
 		if sect != nil {
-			r := make([]byte, ptrdata/int64(Thearch.Ptrsize))
+			r := make([]byte, ptrdata/int64(SysArch.PtrSize))
 			sect.ReadAt(r, int64(addr-sect.Addr))
 			return r
 		}
 		Exitf("cannot find gcmask for %s", s.Name)
 		return nil
 	}
-	mask := decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize))
+	mask := decode_reloc_sym(s, 2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize))
 	return mask.P
 }
 
@@ -150,7 +151,7 @@
 }
 
 func decodetype_arraylen(s *LSym) int64 {
-	return int64(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Ptrsize))
+	return int64(decode_inuxi(s.P[commonsize()+2*SysArch.PtrSize:], SysArch.PtrSize))
 }
 
 // Type.PtrType.elem
@@ -164,7 +165,7 @@
 }
 
 func decodetype_mapvalue(s *LSym) *LSym {
-	return decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)) // 0x20 / 0x38
+	return decode_reloc_sym(s, int32(commonsize())+int32(SysArch.PtrSize)) // 0x20 / 0x38
 }
 
 // Type.ChanType.elem
@@ -188,13 +189,13 @@
 
 func decodetype_funcintype(s *LSym, i int) *LSym {
 	uadd := commonsize() + 4
-	if Thearch.Ptrsize == 8 {
+	if SysArch.PtrSize == 8 {
 		uadd += 4
 	}
 	if decodetype_hasUncommon(s) {
 		uadd += uncommonSize()
 	}
-	return decode_reloc_sym(s, int32(uadd+i*Thearch.Ptrsize))
+	return decode_reloc_sym(s, int32(uadd+i*SysArch.PtrSize))
 }
 
 func decodetype_funcouttype(s *LSym, i int) *LSym {
@@ -203,11 +204,11 @@
 
 // Type.StructType.fields.Slice::length
 func decodetype_structfieldcount(s *LSym) int {
-	return int(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Intsize))
+	return int(decode_inuxi(s.P[commonsize()+2*SysArch.PtrSize:], SysArch.IntSize))
 }
 
 func decodetype_structfieldarrayoff(s *LSym, i int) int {
-	off := commonsize() + 2*Thearch.Ptrsize + 2*Thearch.Intsize
+	off := commonsize() + 2*SysArch.PtrSize + 2*SysArch.IntSize
 	if decodetype_hasUncommon(s) {
 		off += uncommonSize()
 	}
@@ -224,7 +225,7 @@
 	if r == nil {           // shouldn't happen.
 		return ""
 	}
-	strlen := int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Intsize))
+	strlen := int64(decode_inuxi(s.P[SysArch.PtrSize:], SysArch.IntSize))
 	return string(r.Sym.P[r.Add : r.Add+strlen])
 }
 
@@ -248,17 +249,17 @@
 
 func decodetype_structfieldtype(s *LSym, i int) *LSym {
 	off := decodetype_structfieldarrayoff(s, i)
-	return decode_reloc_sym(s, int32(off+Thearch.Ptrsize))
+	return decode_reloc_sym(s, int32(off+SysArch.PtrSize))
 }
 
 func decodetype_structfieldoffs(s *LSym, i int) int64 {
 	off := decodetype_structfieldarrayoff(s, i)
-	return int64(decode_inuxi(s.P[off+2*Thearch.Ptrsize:], Thearch.Intsize))
+	return int64(decode_inuxi(s.P[off+2*SysArch.PtrSize:], SysArch.IntSize))
 }
 
 // InterfaceType.methods.length
 func decodetype_ifacemethodcount(s *LSym) int64 {
-	return int64(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Intsize))
+	return int64(decode_inuxi(s.P[commonsize()+2*SysArch.PtrSize:], SysArch.IntSize))
 }
 
 // methodsig is a fully qualified typed method signature, like
@@ -288,7 +289,7 @@
 	var methods []methodsig
 	for i := 0; i < count; i++ {
 		buf.WriteString(decodetype_name(s, off))
-		mtypSym := decode_reloc_sym(s, int32(off+Thearch.Ptrsize))
+		mtypSym := decode_reloc_sym(s, int32(off+SysArch.PtrSize))
 
 		buf.WriteRune('(')
 		inCount := decodetype_funcincount(mtypSym)
@@ -319,7 +320,7 @@
 	if decodetype_kind(s)&kindMask != kindInterface {
 		panic(fmt.Sprintf("symbol %q is not an interface", s.Name))
 	}
-	r := decode_reloc(s, int32(commonsize()+Thearch.Ptrsize))
+	r := decode_reloc(s, int32(commonsize()+SysArch.PtrSize))
 	if r == nil {
 		return nil
 	}
@@ -328,7 +329,7 @@
 	}
 	off := int(r.Add) // array of reflect.imethod values
 	numMethods := int(decodetype_ifacemethodcount(s))
-	sizeofIMethod := 2 * Thearch.Ptrsize
+	sizeofIMethod := 2 * SysArch.PtrSize
 	return decode_methodsig(s, off, sizeofIMethod, numMethods)
 }
 
@@ -339,31 +340,31 @@
 	off := commonsize() // reflect.rtype
 	switch decodetype_kind(s) & kindMask {
 	case kindStruct: // reflect.structType
-		off += 2*Thearch.Ptrsize + 2*Thearch.Intsize
+		off += 2*SysArch.PtrSize + 2*SysArch.IntSize
 	case kindPtr: // reflect.ptrType
-		off += Thearch.Ptrsize
+		off += SysArch.PtrSize
 	case kindFunc: // reflect.funcType
-		off += Thearch.Ptrsize // 4 bytes, pointer aligned
+		off += SysArch.PtrSize // 4 bytes, pointer aligned
 	case kindSlice: // reflect.sliceType
-		off += Thearch.Ptrsize
+		off += SysArch.PtrSize
 	case kindArray: // reflect.arrayType
-		off += 3 * Thearch.Ptrsize
+		off += 3 * SysArch.PtrSize
 	case kindChan: // reflect.chanType
-		off += 2 * Thearch.Ptrsize
+		off += 2 * SysArch.PtrSize
 	case kindMap: // reflect.mapType
-		off += 4*Thearch.Ptrsize + 8
+		off += 4*SysArch.PtrSize + 8
 	case kindInterface: // reflect.interfaceType
-		off += Thearch.Ptrsize + 2*Thearch.Intsize
+		off += SysArch.PtrSize + 2*SysArch.IntSize
 	default:
 		// just Sizeof(rtype)
 	}
 
-	numMethods := int(decode_inuxi(s.P[off+2*Thearch.Ptrsize:], Thearch.Intsize))
-	r := decode_reloc(s, int32(off+Thearch.Ptrsize))
+	numMethods := int(decode_inuxi(s.P[off+2*SysArch.PtrSize:], SysArch.IntSize))
+	r := decode_reloc(s, int32(off+SysArch.PtrSize))
 	if r.Sym != s {
 		panic(fmt.Sprintf("method slice pointer in %s leads to a different symbol %s", s, r.Sym))
 	}
 	off = int(r.Add)                    // array of reflect.method values
-	sizeofMethod := 4 * Thearch.Ptrsize // sizeof reflect.method in program
+	sizeofMethod := 4 * SysArch.PtrSize // sizeof reflect.method in program
 	return decode_methodsig(s, off, sizeofMethod, numMethods)
 }
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index eaa0bdb..230d146 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -39,7 +39,7 @@
  *  Basic I/O
  */
 func addrput(s *LSym, addr int64) {
-	switch Thearch.Ptrsize {
+	switch SysArch.PtrSize {
 	case 4:
 		Adduint32(Ctxt, s, uint32(addr))
 
@@ -569,7 +569,7 @@
 	default:
 		Diag("invalid size %d in adddwarfref\n", size)
 		fallthrough
-	case Thearch.Ptrsize:
+	case SysArch.PtrSize:
 		result = Addaddr(ctxt, s, t)
 	case 4:
 		result = addaddrplus4(ctxt, s, t, 0)
@@ -599,7 +599,7 @@
 
 	case DW_FORM_block1: // block
 		if cls == DW_CLS_ADDRESS {
-			Adduint8(Ctxt, s, uint8(1+Thearch.Ptrsize))
+			Adduint8(Ctxt, s, uint8(1+SysArch.PtrSize))
 			Adduint8(Ctxt, s, DW_OP_addr)
 			Addaddr(Ctxt, s, data.(*LSym))
 			break
@@ -682,14 +682,14 @@
 	case DW_FORM_ref_addr: // reference to a DIE in the .info section
 		if data == nil {
 			Diag("dwarf: null reference in %d", abbrev)
-			if Thearch.Ptrsize == 8 {
+			if SysArch.PtrSize == 8 {
 				Adduint64(Ctxt, s, 0) // invalid dwarf, gdb will complain.
 			} else {
 				Adduint32(Ctxt, s, 0) // invalid dwarf, gdb will complain.
 			}
 		} else {
 			dsym := data.(*LSym)
-			adddwarfref(Ctxt, s, dsym, Thearch.Ptrsize)
+			adddwarfref(Ctxt, s, dsym, SysArch.PtrSize)
 		}
 
 	case DW_FORM_ref1, // reference within the compilation unit
@@ -1161,11 +1161,11 @@
 		// compute size info like hashmap.c does.
 		indirect_key, indirect_val := false, false
 		if keysize > MaxKeySize {
-			keysize = int64(Thearch.Ptrsize)
+			keysize = int64(SysArch.PtrSize)
 			indirect_key = true
 		}
 		if valsize > MaxValSize {
-			valsize = int64(Thearch.Ptrsize)
+			valsize = int64(SysArch.PtrSize)
 			indirect_val = true
 		}
 
@@ -1212,13 +1212,13 @@
 			fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "overflow", 0)
 			newrefattr(fld, DW_AT_type, defptrto(dwhb.sym))
 			newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize)))
-			if Thearch.Regsize > Thearch.Ptrsize {
+			if SysArch.RegSize > SysArch.PtrSize {
 				fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "pad", 0)
 				newrefattr(fld, DW_AT_type, mustFind("uintptr"))
-				newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(Thearch.Ptrsize))
+				newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(SysArch.PtrSize))
 			}
 
-			newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize+BucketSize*int64(keysize)+BucketSize*int64(valsize)+int64(Thearch.Regsize), 0)
+			newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize+BucketSize*int64(keysize)+BucketSize*int64(valsize)+int64(SysArch.RegSize), 0)
 		})
 
 		// Construct hash<K,V>
@@ -1481,7 +1481,7 @@
 	headerend = ls.Size
 
 	Adduint8(Ctxt, ls, 0) // start extended opcode
-	uleb128put(ls, 1+int64(Thearch.Ptrsize))
+	uleb128put(ls, 1+int64(SysArch.PtrSize))
 	Adduint8(Ctxt, ls, DW_LNE_set_address)
 
 	pc := s.Value
@@ -1555,7 +1555,7 @@
 				dt = DW_ABRV_AUTO
 				offs = int64(a.Aoffset)
 				if !haslinkregister() {
-					offs -= int64(Thearch.Ptrsize)
+					offs -= int64(SysArch.PtrSize)
 				}
 
 			case obj.A_PARAM:
@@ -1667,7 +1667,7 @@
 	if haslinkregister() {
 		uleb128put(fs, int64(0)) // offset
 	} else {
-		uleb128put(fs, int64(Thearch.Ptrsize)) // offset
+		uleb128put(fs, int64(SysArch.PtrSize)) // offset
 	}
 
 	Adduint8(Ctxt, fs, DW_CFA_offset_extended)
@@ -1675,7 +1675,7 @@
 	if haslinkregister() {
 		uleb128put(fs, int64(0)/DATAALIGNMENTFACTOR) // at cfa - 0
 	} else {
-		uleb128put(fs, int64(-Thearch.Ptrsize)/DATAALIGNMENTFACTOR) // at cfa - x*4
+		uleb128put(fs, int64(-SysArch.PtrSize)/DATAALIGNMENTFACTOR) // at cfa - x*4
 	}
 
 	// 4 is to exclude the length field.
@@ -1713,10 +1713,10 @@
 			if haslinkregister() {
 				deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(pcsp.value))
 			} else {
-				deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(Thearch.Ptrsize)+int64(pcsp.value))
+				deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(SysArch.PtrSize)+int64(pcsp.value))
 			}
 		}
-		pad := int(Rnd(int64(len(deltaBuf)), int64(Thearch.Ptrsize))) - len(deltaBuf)
+		pad := int(Rnd(int64(len(deltaBuf)), int64(SysArch.PtrSize))) - len(deltaBuf)
 		deltaBuf = append(deltaBuf, zeros[:pad]...)
 
 		// Emit the FDE header, Section 6.4.1.
@@ -1724,7 +1724,7 @@
 		//	4 bytes: Pointer to the CIE above, at offset 0
 		//	ptrsize: initial location
 		//	ptrsize: address range
-		Adduint32(Ctxt, fs, uint32(4+2*Thearch.Ptrsize+len(deltaBuf))) // length (excludes itself)
+		Adduint32(Ctxt, fs, uint32(4+2*SysArch.PtrSize+len(deltaBuf))) // length (excludes itself)
 		if Linkmode == LinkExternal {
 			adddwarfref(Ctxt, fs, framesec, 4)
 		} else {
@@ -1771,7 +1771,7 @@
 		// debug_abbrev_offset (*)
 		adddwarfref(Ctxt, s, abbrevsym, 4)
 
-		Adduint8(Ctxt, s, uint8(Thearch.Ptrsize)) // address_size
+		Adduint8(Ctxt, s, uint8(SysArch.PtrSize)) // address_size
 
 		prev = putdie(prev, compunit)
 		cusize := s.Size - 4 // exclude the length field.
@@ -1848,7 +1848,7 @@
 	s.Type = obj.SDWARFSECT
 	// The first tuple is aligned to a multiple of the size of a single tuple
 	// (twice the size of an address)
-	headersize := int(Rnd(4+2+4+1+1, int64(Thearch.Ptrsize*2))) // don't count unit_length field itself
+	headersize := int(Rnd(4+2+4+1+1, int64(SysArch.PtrSize*2))) // don't count unit_length field itself
 
 	for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
 		b := getattr(compunit, DW_AT_low_pc)
@@ -1861,13 +1861,13 @@
 		}
 
 		// Write .debug_aranges	 Header + entry	 (sec 6.1.2)
-		unitlength := uint32(headersize) + 4*uint32(Thearch.Ptrsize) - 4
+		unitlength := uint32(headersize) + 4*uint32(SysArch.PtrSize) - 4
 		Adduint32(Ctxt, s, unitlength) // unit_length (*)
 		Adduint16(Ctxt, s, 2)          // dwarf version (appendix F)
 
 		adddwarfref(Ctxt, s, compunit.sym, 4)
 
-		Adduint8(Ctxt, s, uint8(Thearch.Ptrsize)) // address_size
+		Adduint8(Ctxt, s, uint8(SysArch.PtrSize)) // address_size
 		Adduint8(Ctxt, s, 0)                      // segment_size
 		padding := headersize - (4 + 2 + 4 + 1 + 1)
 		for i := 0; i < padding; i++ {
@@ -1940,7 +1940,7 @@
 
 	die := newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr", 0) // needed for array size
 	newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0)
-	newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, int64(Thearch.Ptrsize), 0)
+	newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, int64(SysArch.PtrSize), 0)
 	newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, obj.KindUintptr, 0)
 
 	// Prototypes needed for type synthesis.
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index 035826d..7c76077 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -6,6 +6,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"crypto/sha1"
 	"encoding/binary"
 	"encoding/hex"
@@ -866,25 +867,23 @@
 func Elfinit() {
 	Iself = true
 
-	switch Thearch.Thechar {
-	case '0', '6', '7', '9', 'z':
+	if SysArch.InFamily(sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.S390X) {
 		elfRelType = ".rela"
-	default:
+	} else {
 		elfRelType = ".rel"
 	}
 
-	switch Thearch.Thechar {
+	switch SysArch.Family {
 	// 64-bit architectures
-	case '9', 'z':
+	case sys.PPC64, sys.S390X:
 		if Ctxt.Arch.ByteOrder == binary.BigEndian {
 			ehdr.flags = 1 /* Version 1 ABI */
 		} else {
 			ehdr.flags = 2 /* Version 2 ABI */
 		}
 		fallthrough
-
-	case '0', '6', '7':
-		if Thearch.Thechar == '0' {
+	case sys.AMD64, sys.ARM64, sys.MIPS64:
+		if SysArch.Family == sys.MIPS64 {
 			ehdr.flags = 0x20000000 /* MIPS 3 */
 		}
 		elf64 = true
@@ -897,7 +896,7 @@
 
 	// we use EABI on both linux/arm and freebsd/arm.
 	// 32-bit architectures
-	case '5':
+	case sys.ARM:
 		// we use EABI on both linux/arm and freebsd/arm.
 		if HEADTYPE == obj.Hlinux || HEADTYPE == obj.Hfreebsd {
 			// We set a value here that makes no indication of which
@@ -911,7 +910,6 @@
 			ehdr.flags = 0x5000002 // has entry point, Version5 EABI
 		}
 		fallthrough
-
 	default:
 		ehdr.phoff = ELF32HDRSIZE
 		/* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */
@@ -1432,7 +1430,7 @@
 	}
 
 	// s390x (ELF64) hash table entries are 8 bytes
-	if Thearch.Thechar == 'z' {
+	if SysArch.Family == sys.S390X {
 		Adduint64(Ctxt, s, uint64(nbucket))
 		Adduint64(Ctxt, s, uint64(nsym))
 		for i := 0; i < nbucket; i++ {
@@ -1660,15 +1658,15 @@
 
 	sh := elfshname(elfRelType + sect.Name)
 	sh.type_ = uint32(typ)
-	sh.entsize = uint64(Thearch.Regsize) * 2
+	sh.entsize = uint64(SysArch.RegSize) * 2
 	if typ == SHT_RELA {
-		sh.entsize += uint64(Thearch.Regsize)
+		sh.entsize += uint64(SysArch.RegSize)
 	}
 	sh.link = uint32(elfshname(".symtab").shnum)
 	sh.info = uint32(sect.Elfsect.shnum)
 	sh.off = sect.Reloff
 	sh.size = sect.Rellen
-	sh.addralign = uint64(Thearch.Regsize)
+	sh.addralign = uint64(SysArch.RegSize)
 	return sh
 }
 
@@ -1872,7 +1870,7 @@
 		Addstring(shstrtab, ".interp")
 		Addstring(shstrtab, ".hash")
 		Addstring(shstrtab, ".got")
-		if Thearch.Thechar == '9' {
+		if SysArch.Family == sys.PPC64 {
 			Addstring(shstrtab, ".glink")
 		}
 		Addstring(shstrtab, ".got.plt")
@@ -1919,7 +1917,7 @@
 		s.Type = obj.SELFGOT // writable
 
 		/* ppc64 glink resolver */
-		if Thearch.Thechar == '9' {
+		if SysArch.Family == sys.PPC64 {
 			s := Linklookup(Ctxt, ".glink", 0)
 			s.Attr |= AttrReachable
 			s.Type = obj.SELFRXSECT
@@ -1938,7 +1936,7 @@
 		s = Linklookup(Ctxt, ".plt", 0)
 
 		s.Attr |= AttrReachable
-		if Thearch.Thechar == '9' {
+		if SysArch.Family == sys.PPC64 {
 			// In the ppc64 ABI, .plt is a data section
 			// written by the dynamic linker.
 			s.Type = obj.SELFSECT
@@ -1993,15 +1991,15 @@
 			Elfwritedynent(s, DT_RUNPATH, uint64(Addstring(dynstr, rpath.val)))
 		}
 
-		if Thearch.Thechar == '9' {
+		if SysArch.Family == sys.PPC64 {
 			elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".plt", 0))
-		} else if Thearch.Thechar == 'z' {
+		} else if SysArch.Family == sys.S390X {
 			elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".got", 0))
 		} else {
 			elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".got.plt", 0))
 		}
 
-		if Thearch.Thechar == '9' {
+		if SysArch.Family == sys.PPC64 {
 			Elfwritedynent(s, DT_PPC64_OPT, 0)
 		}
 
@@ -2080,22 +2078,22 @@
 
 func Asmbelf(symo int64) {
 	eh := getElfEhdr()
-	switch Thearch.Thechar {
+	switch SysArch.Family {
 	default:
-		Exitf("unknown architecture in asmbelf: %v", Thearch.Thechar)
-	case '0':
+		Exitf("unknown architecture in asmbelf: %v", SysArch.Family)
+	case sys.MIPS64:
 		eh.machine = EM_MIPS
-	case '5':
+	case sys.ARM:
 		eh.machine = EM_ARM
-	case '6':
+	case sys.AMD64:
 		eh.machine = EM_X86_64
-	case '7':
+	case sys.ARM64:
 		eh.machine = EM_AARCH64
-	case '8':
+	case sys.I386:
 		eh.machine = EM_386
-	case '9':
+	case sys.PPC64:
 		eh.machine = EM_PPC64
-	case 'z':
+	case sys.S390X:
 		eh.machine = EM_S390
 	}
 
@@ -2251,7 +2249,7 @@
 		} else {
 			sh.entsize = ELF32SYMSIZE
 		}
-		sh.addralign = uint64(Thearch.Regsize)
+		sh.addralign = uint64(SysArch.RegSize)
 		sh.link = uint32(elfshname(".dynstr").shnum)
 
 		// sh->info = index of first non-local symbol (number of local symbols)
@@ -2275,7 +2273,7 @@
 			sh = elfshname(".gnu.version_r")
 			sh.type_ = SHT_GNU_VERNEED
 			sh.flags = SHF_ALLOC
-			sh.addralign = uint64(Thearch.Regsize)
+			sh.addralign = uint64(SysArch.RegSize)
 			sh.info = uint32(elfverneed)
 			sh.link = uint32(elfshname(".dynstr").shnum)
 			shsym(sh, Linklookup(Ctxt, ".gnu.version_r", 0))
@@ -2286,7 +2284,7 @@
 			sh.type_ = SHT_RELA
 			sh.flags = SHF_ALLOC
 			sh.entsize = ELF64RELASIZE
-			sh.addralign = uint64(Thearch.Regsize)
+			sh.addralign = uint64(SysArch.RegSize)
 			sh.link = uint32(elfshname(".dynsym").shnum)
 			sh.info = uint32(elfshname(".plt").shnum)
 			shsym(sh, Linklookup(Ctxt, ".rela.plt", 0))
@@ -2350,15 +2348,15 @@
 			sh := elfshname(".got")
 			sh.type_ = SHT_PROGBITS
 			sh.flags = SHF_ALLOC + SHF_WRITE
-			sh.entsize = uint64(Thearch.Regsize)
-			sh.addralign = uint64(Thearch.Regsize)
+			sh.entsize = uint64(SysArch.RegSize)
+			sh.addralign = uint64(SysArch.RegSize)
 			shsym(sh, Linklookup(Ctxt, ".got", 0))
 
 			sh = elfshname(".got.plt")
 			sh.type_ = SHT_PROGBITS
 			sh.flags = SHF_ALLOC + SHF_WRITE
-			sh.entsize = uint64(Thearch.Regsize)
-			sh.addralign = uint64(Thearch.Regsize)
+			sh.entsize = uint64(SysArch.RegSize)
+			sh.addralign = uint64(SysArch.RegSize)
 			shsym(sh, Linklookup(Ctxt, ".got.plt", 0))
 		}
 
@@ -2366,7 +2364,7 @@
 		sh.type_ = SHT_HASH
 		sh.flags = SHF_ALLOC
 		sh.entsize = 4
-		sh.addralign = uint64(Thearch.Regsize)
+		sh.addralign = uint64(SysArch.RegSize)
 		sh.link = uint32(elfshname(".dynsym").shnum)
 		shsym(sh, Linklookup(Ctxt, ".hash", 0))
 
@@ -2375,8 +2373,8 @@
 
 		sh.type_ = SHT_DYNAMIC
 		sh.flags = SHF_ALLOC + SHF_WRITE
-		sh.entsize = 2 * uint64(Thearch.Regsize)
-		sh.addralign = uint64(Thearch.Regsize)
+		sh.entsize = 2 * uint64(SysArch.RegSize)
+		sh.addralign = uint64(SysArch.RegSize)
 		sh.link = uint32(elfshname(".dynstr").shnum)
 		shsym(sh, Linklookup(Ctxt, ".dynamic", 0))
 		ph := newElfPhdr()
@@ -2402,7 +2400,7 @@
 				ph.type_ = PT_TLS
 				ph.flags = PF_R
 				ph.memsz = tlssize
-				ph.align = uint64(Thearch.Regsize)
+				ph.align = uint64(SysArch.RegSize)
 			}
 		}
 	}
@@ -2411,12 +2409,12 @@
 		ph := newElfPhdr()
 		ph.type_ = PT_GNU_STACK
 		ph.flags = PF_W + PF_R
-		ph.align = uint64(Thearch.Regsize)
+		ph.align = uint64(SysArch.RegSize)
 
 		ph = newElfPhdr()
 		ph.type_ = PT_PAX_FLAGS
 		ph.flags = 0x2a00 // mprotect, randexec, emutramp disabled
-		ph.align = uint64(Thearch.Regsize)
+		ph.align = uint64(SysArch.RegSize)
 	}
 
 elfobj:
@@ -2476,8 +2474,8 @@
 		sh.type_ = SHT_SYMTAB
 		sh.off = uint64(symo)
 		sh.size = uint64(Symsize)
-		sh.addralign = uint64(Thearch.Regsize)
-		sh.entsize = 8 + 2*uint64(Thearch.Regsize)
+		sh.addralign = uint64(SysArch.RegSize)
+		sh.entsize = 8 + 2*uint64(SysArch.RegSize)
 		sh.link = uint32(elfshname(".strtab").shnum)
 		sh.info = uint32(elfglobalsymndx)
 
@@ -2600,7 +2598,7 @@
 		/* size of object */
 		Adduint64(ctxt, d, uint64(s.Size))
 
-		if Thearch.Thechar == '6' && !s.Attr.CgoExportDynamic() && s.Dynimplib != "" && !seenlib[s.Dynimplib] {
+		if SysArch.Family == sys.AMD64 && !s.Attr.CgoExportDynamic() && s.Dynimplib != "" && !seenlib[s.Dynimplib] {
 			Elfwritedynent(Linklookup(ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(Linklookup(ctxt, ".dynstr", 0), s.Dynimplib)))
 		}
 	} else {
@@ -2628,9 +2626,9 @@
 		t := STB_GLOBAL << 4
 
 		// TODO(mwhudson): presumably the behaviour should actually be the same on both arm and 386.
-		if Thearch.Thechar == '8' && s.Attr.CgoExport() && s.Type&obj.SMASK == obj.STEXT {
+		if SysArch.Family == sys.I386 && s.Attr.CgoExport() && s.Type&obj.SMASK == obj.STEXT {
 			t |= STT_FUNC
-		} else if Thearch.Thechar == '5' && s.Attr.CgoExportDynamic() && s.Type&obj.SMASK == obj.STEXT {
+		} else if SysArch.Family == sys.ARM && s.Attr.CgoExportDynamic() && s.Type&obj.SMASK == obj.STEXT {
 			t |= STT_FUNC
 		} else {
 			t |= STT_OBJECT
diff --git a/src/cmd/link/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go
index 0255331..3aee2d5 100644
--- a/src/cmd/link/internal/ld/ldelf.go
+++ b/src/cmd/link/internal/ld/ldelf.go
@@ -3,6 +3,7 @@
 import (
 	"bytes"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"encoding/binary"
 	"fmt"
 	"io"
@@ -546,47 +547,48 @@
 		return
 	}
 
-	switch Thearch.Thechar {
+	switch SysArch.Family {
 	default:
-		Diag("%s: elf %s unimplemented", pn, Thestring)
+		Diag("%s: elf %s unimplemented", pn, SysArch.Name)
 		return
 
-	case '0':
+	case sys.MIPS64:
 		if elfobj.machine != ElfMachMips || hdr.Ident[4] != ElfClass64 {
 			Diag("%s: elf object but not mips64", pn)
 			return
 		}
 
-	case '5':
+	case sys.ARM:
 		if e != binary.LittleEndian || elfobj.machine != ElfMachArm || hdr.Ident[4] != ElfClass32 {
 			Diag("%s: elf object but not arm", pn)
 			return
 		}
 
-	case '6':
+	case sys.AMD64:
 		if e != binary.LittleEndian || elfobj.machine != ElfMachAmd64 || hdr.Ident[4] != ElfClass64 {
 			Diag("%s: elf object but not amd64", pn)
 			return
 		}
 
-	case '7':
+	case sys.ARM64:
 		if e != binary.LittleEndian || elfobj.machine != ElfMachArm64 || hdr.Ident[4] != ElfClass64 {
 			Diag("%s: elf object but not arm64", pn)
 			return
 		}
 
-	case '8':
+	case sys.I386:
 		if e != binary.LittleEndian || elfobj.machine != ElfMach386 || hdr.Ident[4] != ElfClass32 {
 			Diag("%s: elf object but not 386", pn)
 			return
 		}
 
-	case '9':
+	case sys.PPC64:
 		if elfobj.machine != ElfMachPower64 || hdr.Ident[4] != ElfClass64 {
 			Diag("%s: elf object but not ppc64", pn)
 			return
 		}
-	case 'z':
+
+	case sys.S390X:
 		if elfobj.machine != ElfMachS390 || hdr.Ident[4] != ElfClass64 {
 			Diag("%s: elf object but not s390x", pn)
 			return
@@ -1056,7 +1058,7 @@
 			}
 
 		case ElfSymBindLocal:
-			if Thearch.Thechar == '5' && (strings.HasPrefix(sym.name, "$a") || strings.HasPrefix(sym.name, "$d")) {
+			if SysArch.Family == sys.ARM && (strings.HasPrefix(sym.name, "$a") || strings.HasPrefix(sym.name, "$d")) {
 				// binutils for arm generate these mapping
 				// symbols, ignore these
 				break
@@ -1127,7 +1129,9 @@
 }
 
 func reltype(pn string, elftype int, siz *uint8) int {
-	switch uint32(Thearch.Thechar) | uint32(elftype)<<24 {
+	// TODO(mdempsky): Remove dependency on ArchFamily char values.
+
+	switch uint32(SysArch.Family) | uint32(elftype)<<24 {
 	default:
 		Diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype)
 		fallthrough
diff --git a/src/cmd/link/internal/ld/ldmacho.go b/src/cmd/link/internal/ld/ldmacho.go
index c4c13f1..9fbb212 100644
--- a/src/cmd/link/internal/ld/ldmacho.go
+++ b/src/cmd/link/internal/ld/ldmacho.go
@@ -2,6 +2,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"encoding/binary"
 	"fmt"
 	"log"
@@ -471,18 +472,18 @@
 	m.length = length
 	m.name = pn
 
-	switch Thearch.Thechar {
+	switch SysArch.Family {
 	default:
-		Diag("%s: mach-o %s unimplemented", pn, Thestring)
+		Diag("%s: mach-o %s unimplemented", pn, SysArch.Name)
 		return
 
-	case '6':
+	case sys.AMD64:
 		if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
 			Diag("%s: mach-o object but not amd64", pn)
 			return
 		}
 
-	case '8':
+	case sys.I386:
 		if e != binary.LittleEndian || m.cputype != LdMachoCpu386 {
 			Diag("%s: mach-o object but not 386", pn)
 			return
@@ -724,10 +725,9 @@
 			rp = &r[rpi]
 			rel = &sect.rel[j]
 			if rel.scattered != 0 {
-				if Thearch.Thechar != '8' {
+				if SysArch.Family != sys.I386 {
 					// mach-o only uses scattered relocation on 32-bit platforms
 					Diag("unexpected scattered relocation")
-
 					continue
 				}
 
@@ -821,7 +821,7 @@
 			rp.Off = int32(rel.addr)
 
 			// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
-			if Thearch.Thechar == '6' && rel.extrn == 0 && rel.type_ == 1 {
+			if SysArch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == 1 {
 				// Calculate the addend as the offset into the section.
 				//
 				// The rip-relative offset stored in the object file is encoded
@@ -847,7 +847,7 @@
 			// For i386 Mach-O PC-relative, the addend is written such that
 			// it *is* the PC being subtracted. Use that to make
 			// it match our version of PC-relative.
-			if rel.pcrel != 0 && Thearch.Thechar == '8' {
+			if rel.pcrel != 0 && SysArch.Family == sys.I386 {
 				rp.Add += int64(rp.Off) + int64(rp.Siz)
 			}
 			if rel.extrn == 0 {
@@ -866,7 +866,7 @@
 				// include that information in the addend.
 				// We only care about the delta from the
 				// section base.
-				if Thearch.Thechar == '8' {
+				if SysArch.Family == sys.I386 {
 					rp.Add -= int64(c.seg.sect[rel.symnum-1].addr)
 				}
 			} else {
diff --git a/src/cmd/link/internal/ld/ldpe.go b/src/cmd/link/internal/ld/ldpe.go
index 5c3e99c..ea0c482 100644
--- a/src/cmd/link/internal/ld/ldpe.go
+++ b/src/cmd/link/internal/ld/ldpe.go
@@ -6,6 +6,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"encoding/binary"
 	"fmt"
 	"log"
@@ -492,7 +493,7 @@
 		if strings.HasPrefix(name, "__imp_") {
 			name = name[6:] // __imp_Name => Name
 		}
-		if Thearch.Thechar == '8' && name[0] == '_' {
+		if SysArch.Family == sys.I386 && name[0] == '_' {
 			name = name[1:] // _Name => Name
 		}
 	}
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 5616700..3e0bd8e 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -34,6 +34,7 @@
 	"bufio"
 	"bytes"
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"crypto/sha1"
 	"debug/elf"
 	"encoding/binary"
@@ -82,14 +83,9 @@
 // THE SOFTWARE.
 
 type Arch struct {
-	Thechar          int
-	Ptrsize          int
-	Intsize          int
-	Regsize          int
 	Funcalign        int
 	Maxalign         int
 	Minalign         int
-	Minlc            int
 	Dwarfregsp       int
 	Dwarfreglr       int
 	Linuxdynld       string
@@ -191,8 +187,7 @@
 }
 
 var (
-	Thestring          string
-	Thelinkarch        *LinkArch
+	SysArch            *sys.Arch
 	outfile            string
 	dynexp             []*LSym
 	dynlib             []string
@@ -509,7 +504,7 @@
 	}
 
 	loadinternal("runtime")
-	if Thearch.Thechar == '5' {
+	if SysArch.Family == sys.ARM {
 		loadinternal("math")
 	}
 	if flag_race != 0 {
@@ -562,7 +557,7 @@
 		// dependency problems when compiling natively (external linking requires
 		// runtime/cgo, runtime/cgo requires cmd/cgo, but cmd/cgo needs to be
 		// compiled using external linking.)
-		if (Thearch.Thechar == '5' || Thearch.Thechar == '7') && HEADTYPE == obj.Hdarwin && iscgo {
+		if SysArch.InFamily(sys.ARM, sys.ARM64) && HEADTYPE == obj.Hdarwin && iscgo {
 			Linkmode = LinkExternal
 		}
 
@@ -621,7 +616,7 @@
 	// a variable to hold g in assembly (currently only intel).
 	if tlsg.Type == 0 {
 		tlsg.Type = obj.STLSBSS
-		tlsg.Size = int64(Thearch.Ptrsize)
+		tlsg.Size = int64(SysArch.PtrSize)
 	} else if tlsg.Type != obj.SDYNIMPORT {
 		Diag("internal error: runtime declared tlsg variable %d", tlsg.Type)
 	}
@@ -639,7 +634,7 @@
 
 		// In addition, on ARM, the runtime depends on the linker
 		// recording the value of GOARM.
-		if Thearch.Thechar == '5' {
+		if SysArch.Family == sys.ARM {
 			s := Linklookup(Ctxt, "runtime.goarm", 0)
 
 			s.Type = obj.SRODATA
@@ -1226,7 +1221,7 @@
 
 	if Debug['s'] == 0 && debug_s == 0 && HEADTYPE == obj.Hdarwin {
 		// Skip combining dwarf on arm.
-		if Thearch.Thechar != '5' && Thearch.Thechar != '7' {
+		if !SysArch.InFamily(sys.ARM, sys.ARM64) {
 			dsym := filepath.Join(tmpdir, "go.dwarf")
 			if out, err := exec.Command("dsymutil", "-f", outfile, "-o", dsym).CombinedOutput(); err != nil {
 				Ctxt.Cursym = nil
@@ -1254,14 +1249,14 @@
 // hostlinkArchArgs returns arguments to pass to the external linker
 // based on the architecture.
 func hostlinkArchArgs() []string {
-	switch Thearch.Thechar {
-	case '8':
+	switch SysArch.Family {
+	case sys.I386:
 		return []string{"-m32"}
-	case '6', '9', 'z':
+	case sys.AMD64, sys.PPC64, sys.S390X:
 		return []string{"-m64"}
-	case '5':
+	case sys.ARM:
 		return []string{"-marm"}
-	case '7':
+	case sys.ARM64:
 		// nothing needed
 	}
 	return nil
@@ -1306,10 +1301,10 @@
 
 	if !strings.HasPrefix(line, "go object ") {
 		if strings.HasSuffix(pn, ".go") {
-			Exitf("%cl: input %s is not .%c file (use %cg to compile .go files)", Thearch.Thechar, pn, Thearch.Thechar, Thearch.Thechar)
+			Exitf("%cl: input %s is not .%c file (use %cg to compile .go files)", SysArch.Family, pn, SysArch.Family, SysArch.Family)
 		}
 
-		if line == Thestring {
+		if line == SysArch.Name {
 			// old header format: just $GOOS
 			Diag("%s: stale object file", pn)
 			return nil
@@ -1500,12 +1495,12 @@
 			// the type data.
 			if strings.HasPrefix(lsym.Name, "type.") && !strings.HasPrefix(lsym.Name, "type..") {
 				lsym.P = readelfsymboldata(f, &elfsym)
-				gcdata_locations[elfsym.Value+2*uint64(Thearch.Ptrsize)+8+1*uint64(Thearch.Ptrsize)] = lsym
+				gcdata_locations[elfsym.Value+2*uint64(SysArch.PtrSize)+8+1*uint64(SysArch.PtrSize)] = lsym
 			}
 		}
 	}
 	gcdata_addresses := make(map[*LSym]uint64)
-	if Thearch.Thechar == '7' {
+	if SysArch.Family == sys.ARM64 {
 		for _, sect := range f.Sections {
 			if sect.Type == elf.SHT_RELA {
 				var rela elf.Rela64
@@ -1565,8 +1560,8 @@
 	goos = obj.Getgoos()
 	goarch = obj.Getgoarch()
 
-	if !strings.HasPrefix(goarch, Thestring) {
-		log.Fatalf("cannot use %cc with GOARCH=%s", Thearch.Thechar, goarch)
+	if !strings.HasPrefix(goarch, SysArch.Name) {
+		log.Fatalf("cannot use %cc with GOARCH=%s", SysArch.Family, goarch)
 	}
 }
 
@@ -1608,7 +1603,7 @@
 	sect.Rwx = uint8(rwx)
 	sect.Name = name
 	sect.Seg = seg
-	sect.Align = int32(Thearch.Ptrsize) // everything is at least pointer-aligned
+	sect.Align = int32(SysArch.PtrSize) // everything is at least pointer-aligned
 	*l = sect
 	return sect
 }
@@ -1652,7 +1647,7 @@
 	if haslinkregister() {
 		return 0
 	}
-	return Thearch.Regsize
+	return SysArch.RegSize
 }
 
 func dostkcheck() {
@@ -1986,7 +1981,7 @@
 		put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), s.Gotype)
 
 		// NOTE(ality): acid can't produce a stack trace without .frame symbols
-		put(nil, ".frame", 'm', int64(s.Locals)+int64(Thearch.Ptrsize), 0, 0, nil)
+		put(nil, ".frame", 'm', int64(s.Locals)+int64(SysArch.PtrSize), 0, 0, nil)
 
 		for _, a := range s.Autom {
 			// Emit a or p according to actual offset, even if label is wrong.
@@ -1999,7 +1994,7 @@
 			if a.Name == obj.A_PARAM {
 				off = a.Aoffset
 			} else {
-				off = a.Aoffset - int32(Thearch.Ptrsize)
+				off = a.Aoffset - int32(SysArch.PtrSize)
 			}
 
 			// FP
@@ -2009,8 +2004,8 @@
 			}
 
 			// SP
-			if off <= int32(-Thearch.Ptrsize) {
-				put(nil, a.Asym.Name, 'a', -(int64(off) + int64(Thearch.Ptrsize)), 0, 0, a.Gotype)
+			if off <= int32(-SysArch.PtrSize) {
+				put(nil, a.Asym.Name, 'a', -(int64(off) + int64(SysArch.PtrSize)), 0, 0, a.Gotype)
 				continue
 			}
 		}
diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go
index 67a8559..f081138 100644
--- a/src/cmd/link/internal/ld/link.go
+++ b/src/cmd/link/internal/ld/link.go
@@ -32,8 +32,8 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"debug/elf"
-	"encoding/binary"
 	"fmt"
 )
 
@@ -161,11 +161,9 @@
 }
 
 type Link struct {
-	Thechar   int32
-	Thestring string
 	Goarm     int32
 	Headtype  int
-	Arch      *LinkArch
+	Arch      *sys.Arch
 	Debugvlog int32
 	Bso       *obj.Biobuf
 	Windows   int32
@@ -196,15 +194,15 @@
 // on the stack in the function prologue and so always have a pointer between
 // the hardware stack pointer and the local variable area.
 func (ctxt *Link) FixedFrameSize() int64 {
-	switch ctxt.Arch.Thechar {
-	case '6', '8':
+	switch ctxt.Arch.Family {
+	case sys.AMD64, sys.I386:
 		return 0
-	case '9':
+	case sys.PPC64:
 		// PIC code on ppc64le requires 32 bytes of stack, and it's easier to
 		// just use that much stack always on ppc64x.
-		return int64(4 * ctxt.Arch.Ptrsize)
+		return int64(4 * ctxt.Arch.PtrSize)
 	default:
-		return int64(ctxt.Arch.Ptrsize)
+		return int64(ctxt.Arch.PtrSize)
 	}
 }
 
@@ -213,15 +211,6 @@
 	l.Hash = append(l.Hash, make(map[string]*LSym))
 }
 
-type LinkArch struct {
-	ByteOrder binary.ByteOrder
-	Name      string
-	Thechar   int
-	Minlc     int
-	Ptrsize   int
-	Regsize   int
-}
-
 type Library struct {
 	Objref string
 	Srcref string
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index cafc6b0..25d48fb 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -6,6 +6,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"sort"
 	"strings"
 )
@@ -131,15 +132,7 @@
 var load_budget int = INITIAL_MACHO_HEADR - 2*1024
 
 func Machoinit() {
-	switch Thearch.Thechar {
-	// 64-bit architectures
-	case '6', '7', '9':
-		macho64 = true
-
-		// 32-bit architectures
-	default:
-		break
-	}
+	macho64 = SysArch.RegSize == 8
 }
 
 func getMachoHdr() *MachoHdr {
@@ -356,8 +349,8 @@
 	buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
 
 	var msect *MachoSect
-	if sect.Rwx&1 == 0 && segname != "__DWARF" && (Thearch.Thechar == '7' || // arm64
-		(Thearch.Thechar == '6' && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive))) { // amd64
+	if sect.Rwx&1 == 0 && segname != "__DWARF" && (SysArch.Family == sys.ARM64 ||
+		(SysArch.Family == sys.AMD64 && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive))) {
 		// Darwin external linker on arm64 and on amd64 in c-shared/c-archive buildmode
 		// complains about absolute relocs in __TEXT, so if the section is not
 		// executable, put it in __DATA segment.
@@ -422,23 +415,23 @@
 	va := INITTEXT - int64(HEADR)
 
 	mh := getMachoHdr()
-	switch Thearch.Thechar {
+	switch SysArch.Family {
 	default:
-		Exitf("unknown macho architecture: %v", Thearch.Thechar)
+		Exitf("unknown macho architecture: %v", SysArch.Family)
 
-	case '5':
+	case sys.ARM:
 		mh.cpu = MACHO_CPU_ARM
 		mh.subcpu = MACHO_SUBCPU_ARMV7
 
-	case '6':
+	case sys.AMD64:
 		mh.cpu = MACHO_CPU_AMD64
 		mh.subcpu = MACHO_SUBCPU_X86
 
-	case '7':
+	case sys.ARM64:
 		mh.cpu = MACHO_CPU_ARM64
 		mh.subcpu = MACHO_SUBCPU_ARM64_ALL
 
-	case '8':
+	case sys.I386:
 		mh.cpu = MACHO_CPU_386
 		mh.subcpu = MACHO_SUBCPU_X86
 	}
@@ -449,7 +442,7 @@
 		ms = newMachoSeg("", 40)
 
 		ms.fileoffset = Segtext.Fileoff
-		if Thearch.Thechar == '5' || Buildmode == BuildmodeCArchive {
+		if SysArch.Family == sys.ARM || Buildmode == BuildmodeCArchive {
 			ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff
 		} else {
 			ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
@@ -511,31 +504,31 @@
 	}
 
 	if Linkmode != LinkExternal {
-		switch Thearch.Thechar {
+		switch SysArch.Family {
 		default:
-			Exitf("unknown macho architecture: %v", Thearch.Thechar)
+			Exitf("unknown macho architecture: %v", SysArch.Family)
 
-		case '5':
+		case sys.ARM:
 			ml := newMachoLoad(5, 17+2)          /* unix thread */
 			ml.data[0] = 1                       /* thread type */
 			ml.data[1] = 17                      /* word count */
 			ml.data[2+15] = uint32(Entryvalue()) /* start pc */
 
-		case '6':
+		case sys.AMD64:
 			ml := newMachoLoad(5, 42+2)          /* unix thread */
 			ml.data[0] = 4                       /* thread type */
 			ml.data[1] = 42                      /* word count */
 			ml.data[2+32] = uint32(Entryvalue()) /* start pc */
 			ml.data[2+32+1] = uint32(Entryvalue() >> 32)
 
-		case '7':
+		case sys.ARM64:
 			ml := newMachoLoad(5, 68+2)          /* unix thread */
 			ml.data[0] = 6                       /* thread type */
 			ml.data[1] = 68                      /* word count */
 			ml.data[2+64] = uint32(Entryvalue()) /* start pc */
 			ml.data[2+64+1] = uint32(Entryvalue() >> 32)
 
-		case '8':
+		case sys.I386:
 			ml := newMachoLoad(5, 16+2)          /* unix thread */
 			ml.data[0] = 1                       /* thread type */
 			ml.data[1] = 16                      /* word count */
@@ -546,7 +539,6 @@
 	if Debug['d'] == 0 {
 		// must match domacholink below
 		s1 := Linklookup(Ctxt, ".machosymtab", 0)
-
 		s2 := Linklookup(Ctxt, ".linkedit.plt", 0)
 		s3 := Linklookup(Ctxt, ".linkedit.got", 0)
 		s4 := Linklookup(Ctxt, ".machosymstr", 0)
@@ -729,7 +721,7 @@
 			Adduint8(Ctxt, symtab, 0x01)                // type N_EXT, external symbol
 			Adduint8(Ctxt, symtab, 0)                   // no section
 			Adduint16(Ctxt, symtab, 0)                  // desc
-			adduintxx(Ctxt, symtab, 0, Thearch.Ptrsize) // no value
+			adduintxx(Ctxt, symtab, 0, SysArch.PtrSize) // no value
 		} else {
 			if s.Attr.CgoExport() {
 				Adduint8(Ctxt, symtab, 0x0f)
@@ -747,7 +739,7 @@
 				Adduint8(Ctxt, symtab, uint8(o.Sect.Extnum))
 			}
 			Adduint16(Ctxt, symtab, 0) // desc
-			adduintxx(Ctxt, symtab, uint64(Symaddr(s)), Thearch.Ptrsize)
+			adduintxx(Ctxt, symtab, uint64(Symaddr(s)), SysArch.PtrSize)
 		}
 	}
 }
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
index ff29ce2..471dda7 100644
--- a/src/cmd/link/internal/ld/pcln.go
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -93,7 +93,7 @@
 	it.value = -1
 	it.start = 1
 	it.done = 0
-	it.pcscale = uint32(ctxt.Arch.Minlc)
+	it.pcscale = uint32(ctxt.Arch.MinLC)
 	pciternext(it)
 }
 
@@ -242,12 +242,12 @@
 	}
 
 	pclntabNfunc = nfunc
-	Symgrow(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize)+4)
+	Symgrow(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize)+4)
 	setuint32(Ctxt, ftab, 0, 0xfffffffb)
-	setuint8(Ctxt, ftab, 6, uint8(Thearch.Minlc))
-	setuint8(Ctxt, ftab, 7, uint8(Thearch.Ptrsize))
-	setuintxx(Ctxt, ftab, 8, uint64(nfunc), int64(Thearch.Ptrsize))
-	pclntabPclntabOffset = int32(8 + Thearch.Ptrsize)
+	setuint8(Ctxt, ftab, 6, uint8(SysArch.MinLC))
+	setuint8(Ctxt, ftab, 7, uint8(SysArch.PtrSize))
+	setuintxx(Ctxt, ftab, 8, uint64(nfunc), int64(SysArch.PtrSize))
+	pclntabPclntabOffset = int32(8 + SysArch.PtrSize)
 
 	nfunc = 0
 	var last *LSym
@@ -272,16 +272,16 @@
 		}
 
 		funcstart = int32(len(ftab.P))
-		funcstart += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
+		funcstart += int32(-len(ftab.P)) & (int32(SysArch.PtrSize) - 1)
 
-		setaddr(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize), Ctxt.Cursym)
-		setuintxx(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint64(funcstart), int64(Thearch.Ptrsize))
+		setaddr(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize), Ctxt.Cursym)
+		setuintxx(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize), uint64(funcstart), int64(SysArch.PtrSize))
 
 		// fixed size of struct, checked below
 		off = funcstart
 
-		end = funcstart + int32(Thearch.Ptrsize) + 3*4 + 5*4 + int32(len(pcln.Pcdata))*4 + int32(len(pcln.Funcdata))*int32(Thearch.Ptrsize)
-		if len(pcln.Funcdata) > 0 && (end&int32(Thearch.Ptrsize-1) != 0) {
+		end = funcstart + int32(SysArch.PtrSize) + 3*4 + 5*4 + int32(len(pcln.Pcdata))*4 + int32(len(pcln.Funcdata))*int32(SysArch.PtrSize)
+		if len(pcln.Funcdata) > 0 && (end&int32(SysArch.PtrSize-1) != 0) {
 			end += 4
 		}
 		Symgrow(Ctxt, ftab, int64(end))
@@ -330,25 +330,25 @@
 		// funcdata, must be pointer-aligned and we're only int32-aligned.
 		// Missing funcdata will be 0 (nil pointer).
 		if len(pcln.Funcdata) > 0 {
-			if off&int32(Thearch.Ptrsize-1) != 0 {
+			if off&int32(SysArch.PtrSize-1) != 0 {
 				off += 4
 			}
 			for i = 0; i < int32(len(pcln.Funcdata)); i++ {
 				if pcln.Funcdata[i] == nil {
-					setuintxx(Ctxt, ftab, int64(off)+int64(Thearch.Ptrsize)*int64(i), uint64(pcln.Funcdataoff[i]), int64(Thearch.Ptrsize))
+					setuintxx(Ctxt, ftab, int64(off)+int64(SysArch.PtrSize)*int64(i), uint64(pcln.Funcdataoff[i]), int64(SysArch.PtrSize))
 				} else {
 					// TODO: Dedup.
 					funcdata_bytes += pcln.Funcdata[i].Size
 
-					setaddrplus(Ctxt, ftab, int64(off)+int64(Thearch.Ptrsize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i])
+					setaddrplus(Ctxt, ftab, int64(off)+int64(SysArch.PtrSize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i])
 				}
 			}
 
-			off += int32(len(pcln.Funcdata)) * int32(Thearch.Ptrsize)
+			off += int32(len(pcln.Funcdata)) * int32(SysArch.PtrSize)
 		}
 
 		if off != end {
-			Diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, len(pcln.Pcdata), len(pcln.Funcdata), Thearch.Ptrsize)
+			Diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, len(pcln.Pcdata), len(pcln.Funcdata), SysArch.PtrSize)
 			errorexit()
 		}
 
@@ -357,14 +357,14 @@
 
 	pclntabLastFunc = last
 	// Final entry of table is just end pc.
-	setaddrplus(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize), last, last.Size)
+	setaddrplus(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize), last, last.Size)
 
 	// Start file table.
 	start := int32(len(ftab.P))
 
-	start += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
+	start += int32(-len(ftab.P)) & (int32(SysArch.PtrSize) - 1)
 	pclntabFiletabOffset = start
-	setuint32(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint32(start))
+	setuint32(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize), uint32(start))
 
 	Symgrow(Ctxt, ftab, int64(start)+(int64(Ctxt.Nhistfile)+1)*4)
 	setuint32(Ctxt, ftab, int64(start), uint32(Ctxt.Nhistfile))
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index 5669836..0204b8c 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -6,6 +6,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"encoding/binary"
 	"fmt"
 	"os"
@@ -419,9 +420,9 @@
 func Peinit() {
 	var l int
 
-	switch Thearch.Thechar {
+	switch SysArch.Family {
 	// 64-bit architectures
-	case '6':
+	case sys.AMD64:
 		pe64 = 1
 
 		l = binary.Size(&oh64)
@@ -506,7 +507,7 @@
 			if err != nil {
 				Diag("failed to parse stdcall decoration: %v", err)
 			}
-			m.argsize *= Thearch.Ptrsize
+			m.argsize *= SysArch.PtrSize
 			s.Extname = s.Extname[:i]
 		}
 
@@ -520,10 +521,10 @@
 		for d := dr; d != nil; d = d.next {
 			for m = d.ms; m != nil; m = m.next {
 				m.s.Type = obj.SDATA
-				Symgrow(Ctxt, m.s, int64(Thearch.Ptrsize))
+				Symgrow(Ctxt, m.s, int64(SysArch.PtrSize))
 				dynName := m.s.Extname
 				// only windows/386 requires stdcall decoration
-				if Thearch.Thechar == '8' && m.argsize >= 0 {
+				if SysArch.Family == sys.I386 && m.argsize >= 0 {
 					dynName += fmt.Sprintf("@%d", m.argsize)
 				}
 				dynSym := Linklookup(Ctxt, dynName, 0)
@@ -532,7 +533,7 @@
 				r := Addrel(m.s)
 				r.Sym = dynSym
 				r.Off = 0
-				r.Siz = uint8(Thearch.Ptrsize)
+				r.Siz = uint8(SysArch.PtrSize)
 				r.Type = obj.R_ADDR
 			}
 		}
@@ -546,10 +547,10 @@
 				m.s.Sub = dynamic.Sub
 				dynamic.Sub = m.s
 				m.s.Value = dynamic.Size
-				dynamic.Size += int64(Thearch.Ptrsize)
+				dynamic.Size += int64(SysArch.PtrSize)
 			}
 
-			dynamic.Size += int64(Thearch.Ptrsize)
+			dynamic.Size += int64(SysArch.PtrSize)
 		}
 	}
 
@@ -946,7 +947,7 @@
 		}
 
 		// only windows/386 requires underscore prefix on external symbols
-		if Thearch.Thechar == '8' &&
+		if SysArch.Family == sys.I386 &&
 			Linkmode == LinkExternal &&
 			(s.Type != obj.SDYNIMPORT || s.Attr.CgoExport()) &&
 			s.Name == s.Extname &&
@@ -1002,7 +1003,7 @@
 		for d := dr; d != nil; d = d.next {
 			for m := d.ms; m != nil; m = m.next {
 				s := m.s.R[0].Xsym
-				put(s, s.Name, 'U', 0, int64(Thearch.Ptrsize), 0, nil)
+				put(s, s.Name, 'U', 0, int64(SysArch.PtrSize), 0, nil)
 			}
 		}
 
@@ -1129,12 +1130,12 @@
 }
 
 func Asmbpe() {
-	switch Thearch.Thechar {
+	switch SysArch.Family {
 	default:
-		Exitf("unknown PE architecture: %v", Thearch.Thechar)
-	case '6':
+		Exitf("unknown PE architecture: %v", SysArch.Family)
+	case sys.AMD64:
 		fh.Machine = IMAGE_FILE_MACHINE_AMD64
-	case '8':
+	case sys.I386:
 		fh.Machine = IMAGE_FILE_MACHINE_I386
 	}
 
diff --git a/src/cmd/link/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go
index f48b54e..b9902a5 100644
--- a/src/cmd/link/internal/ld/pobj.go
+++ b/src/cmd/link/internal/ld/pobj.go
@@ -32,6 +32,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"flag"
 	"fmt"
 	"os"
@@ -44,9 +45,7 @@
 )
 
 func Ldmain() {
-	Ctxt = linknew(Thelinkarch)
-	Ctxt.Thechar = int32(Thearch.Thechar)
-	Ctxt.Thestring = Thestring
+	Ctxt = linknew(SysArch)
 	Ctxt.Diag = Diag
 	Ctxt.Bso = &Bso
 
@@ -70,7 +69,7 @@
 		}
 	}
 
-	if Thearch.Thechar == '6' && obj.Getgoos() == "plan9" {
+	if SysArch.Family == sys.AMD64 && obj.Getgoos() == "plan9" {
 		obj.Flagcount("8", "use 64-bit addresses in symbol table", &Debug['8'])
 	}
 	obj.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF", addbuildinfo)
@@ -107,7 +106,7 @@
 	obj.Flagcount("race", "enable race detector", &flag_race)
 	obj.Flagcount("s", "disable symbol table", &Debug['s'])
 	var flagShared int
-	if Thearch.Thechar == '5' || Thearch.Thechar == '6' {
+	if SysArch.InFamily(sys.ARM, sys.AMD64) {
 		obj.Flagcount("shared", "generate shared object (implies -linkmode external)", &flagShared)
 	}
 	obj.Flagstr("tmpdir", "use `directory` for temporary files", &tmpdir)
diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go
index 3deb946..76fe7da 100644
--- a/src/cmd/link/internal/ld/sym.go
+++ b/src/cmd/link/internal/ld/sym.go
@@ -33,6 +33,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"log"
 	"strconv"
 )
@@ -55,7 +56,7 @@
 	{"windowsgui", obj.Hwindows},
 }
 
-func linknew(arch *LinkArch) *Link {
+func linknew(arch *sys.Arch) *Link {
 	ctxt := &Link{
 		Hash: []map[string]*LSym{
 			// preallocate about 2mb for hash of
@@ -98,33 +99,33 @@
 		obj.Hdragonfly,
 		obj.Hsolaris:
 		if obj.Getgoos() == "android" {
-			switch ctxt.Arch.Thechar {
-			case '6':
+			switch ctxt.Arch.Family {
+			case sys.AMD64:
 				// Android/amd64 constant - offset from 0(FS) to our TLS slot.
 				// Explained in src/runtime/cgo/gcc_android_*.c
 				ctxt.Tlsoffset = 0x1d0
-			case '8':
+			case sys.I386:
 				// Android/386 constant - offset from 0(GS) to our TLS slot.
 				ctxt.Tlsoffset = 0xf8
 			default:
-				ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize
+				ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize
 			}
 		} else {
-			ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize
+			ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize
 		}
 
 	case obj.Hnacl:
-		switch ctxt.Arch.Thechar {
+		switch ctxt.Arch.Family {
 		default:
 			log.Fatalf("unknown thread-local storage offset for nacl/%s", ctxt.Arch.Name)
 
-		case '5':
+		case sys.ARM:
 			ctxt.Tlsoffset = 0
 
-		case '6':
+		case sys.AMD64:
 			ctxt.Tlsoffset = 0
 
-		case '8':
+		case sys.I386:
 			ctxt.Tlsoffset = -8
 		}
 
@@ -133,26 +134,26 @@
 		 * Explained in src/runtime/cgo/gcc_darwin_*.c.
 		 */
 	case obj.Hdarwin:
-		switch ctxt.Arch.Thechar {
+		switch ctxt.Arch.Family {
 		default:
 			log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name)
 
-		case '5':
+		case sys.ARM:
 			ctxt.Tlsoffset = 0 // dummy value, not needed
 
-		case '6':
+		case sys.AMD64:
 			ctxt.Tlsoffset = 0x8a0
 
-		case '7':
+		case sys.ARM64:
 			ctxt.Tlsoffset = 0 // dummy value, not needed
 
-		case '8':
+		case sys.I386:
 			ctxt.Tlsoffset = 0x468
 		}
 	}
 
 	// On arm, record goarm.
-	if ctxt.Arch.Thechar == '5' {
+	if ctxt.Arch.Family == sys.ARM {
 		ctxt.Goarm = obj.Getgoarm()
 	}
 
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index 167176c..ecd5c74 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -32,6 +32,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"fmt"
 	"path/filepath"
 	"strings"
@@ -160,7 +161,7 @@
 	if x.Type&obj.SHIDDEN != 0 {
 		other = STV_HIDDEN
 	}
-	if (Buildmode == BuildmodePIE || DynlinkingGo()) && Thearch.Thechar == '9' && type_ == STT_FUNC && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" {
+	if (Buildmode == BuildmodePIE || DynlinkingGo()) && SysArch.Family == sys.PPC64 && type_ == STT_FUNC && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" {
 		// On ppc64 the top three bits of the st_other field indicate how
 		// many instructions separate the global and local entry points. In
 		// our case it is two instructions, indicated by the value 3.
@@ -229,7 +230,7 @@
 		'Z',
 		'm':
 		l := 4
-		if HEADTYPE == obj.Hplan9 && Thearch.Thechar == '6' && Debug['8'] == 0 {
+		if HEADTYPE == obj.Hplan9 && SysArch.Family == sys.AMD64 && Debug['8'] == 0 {
 			Lputb(uint32(addr >> 32))
 			l = 8
 		}
diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go
index d0977e9..9a145e3 100644
--- a/src/cmd/link/internal/mips64/asm.go
+++ b/src/cmd/link/internal/mips64/asm.go
@@ -32,6 +32,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"encoding/binary"
 	"fmt"
@@ -82,8 +83,8 @@
 
 		// the first instruction is always at the lower address, this is endian neutral;
 		// but note that o1 and o2 should still use the target endian.
-		o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off:])
-		o2 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4:])
+		o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
+		o2 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off+4:])
 		o1 = o1&0xffff0000 | uint32(t>>16)&0xffff
 		o2 = o2&0xffff0000 | uint32(t)&0xffff
 
@@ -99,7 +100,7 @@
 		obj.R_JMPMIPS:
 		// Low 26 bits = (S + A) >> 2
 		t := ld.Symaddr(r.Sym) + r.Add
-		o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off:])
+		o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:])
 		*val = int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000)
 		return 0
 	}
@@ -214,7 +215,7 @@
 	default:
 	case obj.Hplan9: /* plan 9 */
 		magic := uint32(4*18*18 + 7)
-		if ld.Thestring == "mips64le" {
+		if ld.SysArch == sys.ArchMIPS64LE {
 			magic = uint32(4*26*26 + 7)
 		}
 		ld.Thearch.Lput(uint32(magic))              /* magic */
diff --git a/src/cmd/link/internal/mips64/l.go b/src/cmd/link/internal/mips64/l.go
index 003ee5c..f4191e6 100644
--- a/src/cmd/link/internal/mips64/l.go
+++ b/src/cmd/link/internal/mips64/l.go
@@ -62,11 +62,9 @@
 // THE SOFTWARE.
 
 const (
-	thechar   = '0'
 	MaxAlign  = 32 // max data alignment
 	MinAlign  = 1  // min data alignment
 	FuncAlign = 8
-	MINLC     = 4
 )
 
 /* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/mips64/obj.go b/src/cmd/link/internal/mips64/obj.go
index 57a1b2a..87bb3a0 100644
--- a/src/cmd/link/internal/mips64/obj.go
+++ b/src/cmd/link/internal/mips64/obj.go
@@ -32,6 +32,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
 	"log"
@@ -45,21 +46,15 @@
 }
 
 func linkarchinit() {
-	ld.Thestring = obj.Getgoarch()
-	if ld.Thestring == "mips64le" {
-		ld.Thelinkarch = &ld.Linkmips64le
+	if obj.Getgoarch() == "mips64le" {
+		ld.SysArch = sys.ArchMIPS64LE
 	} else {
-		ld.Thelinkarch = &ld.Linkmips64
+		ld.SysArch = sys.ArchMIPS64
 	}
 
-	ld.Thearch.Thechar = thechar
-	ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
-	ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
-	ld.Thearch.Regsize = ld.Thelinkarch.Regsize
 	ld.Thearch.Funcalign = FuncAlign
 	ld.Thearch.Maxalign = MaxAlign
 	ld.Thearch.Minalign = MinAlign
-	ld.Thearch.Minlc = MINLC
 	ld.Thearch.Dwarfregsp = DWARFREGSP
 	ld.Thearch.Dwarfreglr = DWARFREGLR
 
@@ -72,7 +67,7 @@
 	ld.Thearch.Elfsetupplt = elfsetupplt
 	ld.Thearch.Gentext = gentext
 	ld.Thearch.Machoreloc1 = machoreloc1
-	if ld.Thelinkarch == &ld.Linkmips64le {
+	if ld.SysArch == sys.ArchMIPS64LE {
 		ld.Thearch.Lput = ld.Lputl
 		ld.Thearch.Wput = ld.Wputl
 		ld.Thearch.Vput = ld.Vputl
diff --git a/src/cmd/link/internal/ppc64/l.go b/src/cmd/link/internal/ppc64/l.go
index 622d6bb..a720993 100644
--- a/src/cmd/link/internal/ppc64/l.go
+++ b/src/cmd/link/internal/ppc64/l.go
@@ -62,11 +62,9 @@
 // THE SOFTWARE.
 
 const (
-	thechar   = '9'
 	MaxAlign  = 32 // max data alignment
 	MinAlign  = 1  // min data alignment
 	FuncAlign = 8
-	MINLC     = 4
 )
 
 /* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/ppc64/obj.go b/src/cmd/link/internal/ppc64/obj.go
index 539ab1a..a540ab8 100644
--- a/src/cmd/link/internal/ppc64/obj.go
+++ b/src/cmd/link/internal/ppc64/obj.go
@@ -32,6 +32,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
 	"log"
@@ -45,21 +46,15 @@
 }
 
 func linkarchinit() {
-	ld.Thestring = obj.Getgoarch()
-	if ld.Thestring == "ppc64le" {
-		ld.Thelinkarch = &ld.Linkppc64le
+	if obj.Getgoarch() == "ppc64le" {
+		ld.SysArch = sys.ArchPPC64LE
 	} else {
-		ld.Thelinkarch = &ld.Linkppc64
+		ld.SysArch = sys.ArchPPC64
 	}
 
-	ld.Thearch.Thechar = thechar
-	ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
-	ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
-	ld.Thearch.Regsize = ld.Thelinkarch.Regsize
 	ld.Thearch.Funcalign = FuncAlign
 	ld.Thearch.Maxalign = MaxAlign
 	ld.Thearch.Minalign = MinAlign
-	ld.Thearch.Minlc = MINLC
 	ld.Thearch.Dwarfregsp = DWARFREGSP
 	ld.Thearch.Dwarfreglr = DWARFREGLR
 
@@ -72,7 +67,7 @@
 	ld.Thearch.Elfsetupplt = elfsetupplt
 	ld.Thearch.Gentext = gentext
 	ld.Thearch.Machoreloc1 = machoreloc1
-	if ld.Thelinkarch == &ld.Linkppc64le {
+	if ld.SysArch == sys.ArchPPC64LE {
 		ld.Thearch.Lput = ld.Lputl
 		ld.Thearch.Wput = ld.Wputl
 		ld.Thearch.Vput = ld.Vputl
@@ -150,7 +145,7 @@
 		}
 
 	case obj.Hlinux: /* ppc64 elf */
-		if ld.Thestring == "ppc64" {
+		if ld.SysArch == sys.ArchPPC64 {
 			ld.Debug['d'] = 1 // TODO(austin): ELF ABI v1 not supported yet
 		}
 		ld.Elfinit()
diff --git a/src/cmd/link/internal/s390x/l.go b/src/cmd/link/internal/s390x/l.go
index 839a984..42cf15e 100644
--- a/src/cmd/link/internal/s390x/l.go
+++ b/src/cmd/link/internal/s390x/l.go
@@ -62,14 +62,9 @@
 // THE SOFTWARE.
 
 const (
-	thechar   = 'z'
-	PtrSize   = 8
-	IntSize   = 8
-	RegSize   = 8
 	MaxAlign  = 32 // max data alignment
 	MinAlign  = 2  // min data alignment
 	FuncAlign = 16
-	MINLC     = 2
 )
 
 /* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/s390x/obj.go b/src/cmd/link/internal/s390x/obj.go
index ef88d22..fdb9898 100644
--- a/src/cmd/link/internal/s390x/obj.go
+++ b/src/cmd/link/internal/s390x/obj.go
@@ -32,6 +32,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
 )
@@ -44,17 +45,11 @@
 }
 
 func linkarchinit() {
-	ld.Thestring = obj.Getgoarch()
-	ld.Thelinkarch = &ld.Links390x
+	ld.SysArch = sys.ArchS390X
 
-	ld.Thearch.Thechar = thechar
-	ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
-	ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
-	ld.Thearch.Regsize = ld.Thelinkarch.Regsize
 	ld.Thearch.Funcalign = FuncAlign
 	ld.Thearch.Maxalign = MaxAlign
 	ld.Thearch.Minalign = MinAlign
-	ld.Thearch.Minlc = MINLC
 	ld.Thearch.Dwarfregsp = DWARFREGSP
 	ld.Thearch.Dwarfreglr = DWARFREGLR
 
diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go
index 7da5dd02..91251de 100644
--- a/src/cmd/link/internal/x86/asm.go
+++ b/src/cmd/link/internal/x86/asm.go
@@ -292,7 +292,7 @@
 			return
 		}
 
-		if ld.HEADTYPE == obj.Hdarwin && s.Size == PtrSize && r.Off == 0 {
+		if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.SysArch.PtrSize) && r.Off == 0 {
 			// Mach-O relocations are a royal pain to lay out.
 			// They use a compact stateful bytecode representation
 			// that is too much bother to deal with.
@@ -317,7 +317,7 @@
 			return
 		}
 
-		if ld.HEADTYPE == obj.Hwindows && s.Size == PtrSize {
+		if ld.HEADTYPE == obj.Hwindows && s.Size == int64(ld.SysArch.PtrSize) {
 			// nothing to do, the relocation will be laid out in pereloc1
 			return
 		}
diff --git a/src/cmd/link/internal/x86/l.go b/src/cmd/link/internal/x86/l.go
index 068fed9..2043f9b 100644
--- a/src/cmd/link/internal/x86/l.go
+++ b/src/cmd/link/internal/x86/l.go
@@ -31,12 +31,9 @@
 package x86
 
 const (
-	thechar   = '8'
-	PtrSize   = 4
 	MaxAlign  = 32 // max data alignment
 	MinAlign  = 1  // min data alignment
 	FuncAlign = 16
-	MINLC     = 1
 )
 
 /* Used by ../internal/ld/dwarf.go */
diff --git a/src/cmd/link/internal/x86/obj.go b/src/cmd/link/internal/x86/obj.go
index 4380c41..574c0da 100644
--- a/src/cmd/link/internal/x86/obj.go
+++ b/src/cmd/link/internal/x86/obj.go
@@ -32,6 +32,7 @@
 
 import (
 	"cmd/internal/obj"
+	"cmd/internal/sys"
 	"cmd/link/internal/ld"
 	"fmt"
 	"log"
@@ -45,17 +46,11 @@
 }
 
 func linkarchinit() {
-	ld.Thestring = "386"
-	ld.Thelinkarch = &ld.Link386
+	ld.SysArch = sys.Arch386
 
-	ld.Thearch.Thechar = thechar
-	ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
-	ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
-	ld.Thearch.Regsize = ld.Thelinkarch.Regsize
 	ld.Thearch.Funcalign = FuncAlign
 	ld.Thearch.Maxalign = MaxAlign
 	ld.Thearch.Minalign = MinAlign
-	ld.Thearch.Minlc = MINLC
 	ld.Thearch.Dwarfregsp = DWARFREGSP
 	ld.Thearch.Dwarfreglr = DWARFREGLR