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 <cherryyz@google.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Vladimir Stefanovic 2016-12-13 21:23:39 +01:00 committed by Ian Lance Taylor
parent 96414ca39f
commit a3b670e333
4 changed files with 96 additions and 17 deletions

View file

@ -184,7 +184,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
// Internally linking cgo is incomplete on some architectures. // Internally linking cgo is incomplete on some architectures.
// https://golang.org/issue/10373 // https://golang.org/issue/10373
// https://golang.org/issue/14449 // 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" return true, obj.GOARCH + " does not support internal cgo"
} }

View file

@ -962,7 +962,7 @@ func Elfinit(ctxt *Link) {
ehdr.flags = 0x5000002 // has entry point, Version5 EABI ehdr.flags = 0x5000002 // has entry point, Version5 EABI
} }
} else if SysArch.Family == sys.MIPS { } else if SysArch.Family == sys.MIPS {
ehdr.flags = 0x50000000 /* MIPS 32 */ ehdr.flags = 0x50001004 /* MIPS 32 CPIC O32*/
} }
fallthrough fallthrough
default: default:

View file

@ -1257,6 +1257,8 @@ func hostlinkArchArgs() []string {
// nothing needed // nothing needed
case sys.MIPS64: case sys.MIPS64:
return []string{"-mabi=64"} return []string{"-mabi=64"}
case sys.MIPS:
return []string{"-mabi=32"}
} }
return nil return nil
} }

View file

@ -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 { func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
ld.Thearch.Lput(uint32(sectoff))
elfsym := r.Xsym.ElfsymForReloc()
switch r.Type {
default:
return -1 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) { func elfsetupplt(ctxt *ld.Link) {
@ -58,9 +84,50 @@ func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
return -1 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 { func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
if ld.Linkmode == ld.LinkExternal { if ld.Linkmode == ld.LinkExternal {
switch r.Type {
default:
return -1 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 { 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)) *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
return 0 return 0
case obj.R_ADDRMIPS, case obj.R_ADDRMIPS, obj.R_ADDRMIPSU:
obj.R_ADDRMIPSU:
t := ld.Symaddr(r.Sym) + r.Add t := ld.Symaddr(r.Sym) + r.Add
o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:]) applyrel(r, s, val, t)
if r.Type == obj.R_ADDRMIPS {
*val = int64(o1&0xffff0000 | uint32(t)&0xffff)
} else {
*val = int64(o1&0xffff0000 | uint32((t+1<<15)>>16)&0xffff)
}
return 0 return 0
case obj.R_CALLMIPS, case obj.R_CALLMIPS, obj.R_JMPMIPS:
obj.R_JMPMIPS:
// Low 26 bits = (S + A) >> 2
t := ld.Symaddr(r.Sym) + r.Add 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 return 0
} }