From a3b670e3333ca0f677a82321d3ad173e01e973a5 Mon Sep 17 00:00:00 2001 From: Vladimir Stefanovic Date: Tue, 13 Dec 2016 21:23:39 +0100 Subject: [PATCH] cmd/link: add external linking support for GOARCH=mips{,le} Fixes #17792. Change-Id: If4f24455eec0edb3b221aef6777a681f6c768866 Reviewed-on: https://go-review.googlesource.com/34313 Reviewed-by: Cherry Zhang Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/config.go | 2 +- src/cmd/link/internal/ld/elf.go | 2 +- src/cmd/link/internal/ld/lib.go | 2 + src/cmd/link/internal/mips/asm.go | 107 +++++++++++++++++++++++++---- 4 files changed, 96 insertions(+), 17 deletions(-) diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index c9ee8847ad..7d00ff1675 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -184,7 +184,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { // Internally linking cgo is incomplete on some architectures. // https://golang.org/issue/10373 // https://golang.org/issue/14449 - if iscgo && SysArch.InFamily(sys.ARM64, sys.MIPS64) { + if iscgo && SysArch.InFamily(sys.ARM64, sys.MIPS64, sys.MIPS) { return true, obj.GOARCH + " does not support internal cgo" } diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index ef9f253414..1d8a5dd35e 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -962,7 +962,7 @@ func Elfinit(ctxt *Link) { ehdr.flags = 0x5000002 // has entry point, Version5 EABI } } else if SysArch.Family == sys.MIPS { - ehdr.flags = 0x50000000 /* MIPS 32 */ + ehdr.flags = 0x50001004 /* MIPS 32 CPIC O32*/ } fallthrough default: diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index a2700d9698..74d79d394c 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1257,6 +1257,8 @@ func hostlinkArchArgs() []string { // nothing needed case sys.MIPS64: return []string{"-mabi=64"} + case sys.MIPS: + return []string{"-mabi=32"} } return nil } diff --git a/src/cmd/link/internal/mips/asm.go b/src/cmd/link/internal/mips/asm.go index b2c72893a1..a591b06dfa 100644 --- a/src/cmd/link/internal/mips/asm.go +++ b/src/cmd/link/internal/mips/asm.go @@ -47,7 +47,33 @@ func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool { } func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int { - return -1 + ld.Thearch.Lput(uint32(sectoff)) + + elfsym := r.Xsym.ElfsymForReloc() + switch r.Type { + default: + return -1 + + case obj.R_ADDR: + if r.Siz != 4 { + return -1 + } + ld.Thearch.Lput(ld.R_MIPS_32 | uint32(elfsym)<<8) + + case obj.R_ADDRMIPS: + ld.Thearch.Lput(ld.R_MIPS_LO16 | uint32(elfsym)<<8) + + case obj.R_ADDRMIPSU: + ld.Thearch.Lput(ld.R_MIPS_HI16 | uint32(elfsym)<<8) + + case obj.R_ADDRMIPSTLS: + ld.Thearch.Lput(ld.R_MIPS_TLS_TPREL_LO16 | uint32(elfsym)<<8) + + case obj.R_CALLMIPS, obj.R_JMPMIPS: + ld.Thearch.Lput(ld.R_MIPS_26 | uint32(elfsym)<<8) + } + + return 0 } func elfsetupplt(ctxt *ld.Link) { @@ -58,9 +84,50 @@ func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int { return -1 } +func applyrel(r *ld.Reloc, s *ld.Symbol, val *int64, t int64) { + o := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:]) + switch r.Type { + case obj.R_ADDRMIPS, obj.R_ADDRMIPSTLS: + *val = int64(o&0xffff0000 | uint32(t)&0xffff) + case obj.R_ADDRMIPSU: + *val = int64(o&0xffff0000 | uint32((t+(1<<15))>>16)&0xffff) + case obj.R_CALLMIPS, obj.R_JMPMIPS: + *val = int64(o&0xfc000000 | uint32(t>>2)&^0xfc000000) + } +} + func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int { if ld.Linkmode == ld.LinkExternal { - return -1 + switch r.Type { + default: + return -1 + + case obj.R_ADDRMIPS, obj.R_ADDRMIPSU: + + r.Done = 0 + + // set up addend for eventual relocation via outer symbol. + rs := r.Sym + r.Xadd = r.Add + for rs.Outer != nil { + r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer) + rs = rs.Outer + } + + if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil { + ld.Errorf(s, "missing section for %s", rs.Name) + } + r.Xsym = rs + applyrel(r, s, val, r.Xadd) + return 0 + + case obj.R_ADDRMIPSTLS, obj.R_CALLMIPS, obj.R_JMPMIPS: + r.Done = 0 + r.Xsym = r.Sym + r.Xadd = r.Add + applyrel(r, s, val, r.Add) + return 0 + } } switch r.Type { @@ -72,23 +139,33 @@ func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int { *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)) return 0 - case obj.R_ADDRMIPS, - obj.R_ADDRMIPSU: + case obj.R_ADDRMIPS, obj.R_ADDRMIPSU: t := ld.Symaddr(r.Sym) + r.Add - o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:]) - if r.Type == obj.R_ADDRMIPS { - *val = int64(o1&0xffff0000 | uint32(t)&0xffff) - } else { - *val = int64(o1&0xffff0000 | uint32((t+1<<15)>>16)&0xffff) - } + applyrel(r, s, val, t) return 0 - case obj.R_CALLMIPS, - obj.R_JMPMIPS: - // Low 26 bits = (S + A) >> 2 + case obj.R_CALLMIPS, obj.R_JMPMIPS: t := ld.Symaddr(r.Sym) + r.Add - o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:]) - *val = int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000) + + if t&3 != 0 { + ld.Errorf(s, "direct call is not aligned: %s %x", r.Sym.Name, t) + } + + // check if target address is in the same 256 MB region as the next instruction + if (s.Value+int64(r.Off)+4)&0xf0000000 != (t & 0xf0000000) { + ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t) + } + + applyrel(r, s, val, t) + return 0 + + case obj.R_ADDRMIPSTLS: + // thread pointer is at 0x7000 offset from the start of TLS data area + t := ld.Symaddr(r.Sym) + r.Add - 0x7000 + if t < -32768 || t >= 32678 { + ld.Errorf(s, "TLS offset out of range %d", t) + } + applyrel(r, s, val, t) return 0 } -- 2.50.0