Commit aa311fec authored by Jordan Rhee's avatar Jordan Rhee Committed by Brad Fitzpatrick

cmd/link: support windows/arm

Enable the Go linker to generate executables for windows/arm.

Generates PE relocation tables, which are used by Windows to
dynamically relocate the Go binary in memory. Windows on ARM
requires all modules to be relocatable, unlike x86/amd64 which are
permitted to have fixed base addresses.

Updates #26148

Change-Id: Ie63964ff52c2377e121b2885e9d05ec3ed8dc1cd
Reviewed-on: https://go-review.googlesource.com/125648
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 39e59da7
...@@ -190,6 +190,9 @@ func (f *peFile) goarch() string { ...@@ -190,6 +190,9 @@ func (f *peFile) goarch() string {
if _, err := findPESymbol(f.pe, "_rt0_amd64_windows"); err == nil { if _, err := findPESymbol(f.pe, "_rt0_amd64_windows"); err == nil {
return "amd64" return "amd64"
} }
if _, err := findPESymbol(f.pe, "_rt0_arm_windows"); err == nil {
return "arm"
}
return "" return ""
} }
......
...@@ -411,6 +411,35 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, se ...@@ -411,6 +411,35 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, se
return true return true
} }
func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
rs := r.Xsym
if rs.Dynid < 0 {
ld.Errorf(s, "reloc %d (%s) to non-coff symbol %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Type, rs.Type)
return false
}
out.Write32(uint32(sectoff))
out.Write32(uint32(rs.Dynid))
var v uint32
switch r.Type {
default:
// unsupported relocation type
return false
case objabi.R_DWARFSECREF:
v = ld.IMAGE_REL_ARM_SECREL
case objabi.R_ADDR:
v = ld.IMAGE_REL_ARM_ADDR32
}
out.Write16(uint16(v))
return true
}
// sign extend a 24-bit integer // sign extend a 24-bit integer
func signext24(x int64) int32 { func signext24(x int64) int32 {
return (int32(x) << 8) >> 8 return (int32(x) << 8) >> 8
...@@ -799,6 +828,10 @@ func asmb(ctxt *ld.Link) { ...@@ -799,6 +828,10 @@ func asmb(ctxt *ld.Link) {
case objabi.Hdarwin: case objabi.Hdarwin:
symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink)) symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink))
case objabi.Hwindows:
symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
} }
ctxt.Out.SeekSet(int64(symo)) ctxt.Out.SeekSet(int64(symo))
...@@ -828,6 +861,11 @@ func asmb(ctxt *ld.Link) { ...@@ -828,6 +861,11 @@ func asmb(ctxt *ld.Link) {
ctxt.Out.Flush() ctxt.Out.Flush()
} }
case objabi.Hwindows:
if ctxt.Debugvlog != 0 {
ctxt.Logf("%5.2f dwarf\n", ld.Cputime())
}
case objabi.Hdarwin: case objabi.Hdarwin:
if ctxt.LinkMode == ld.LinkExternal { if ctxt.LinkMode == ld.LinkExternal {
ld.Machoemitreloc(ctxt) ld.Machoemitreloc(ctxt)
...@@ -860,6 +898,9 @@ func asmb(ctxt *ld.Link) { ...@@ -860,6 +898,9 @@ func asmb(ctxt *ld.Link) {
case objabi.Hdarwin: case objabi.Hdarwin:
ld.Asmbmacho(ctxt) ld.Asmbmacho(ctxt)
case objabi.Hwindows:
ld.Asmbpe(ctxt)
} }
ctxt.Out.Flush() ctxt.Out.Flush()
......
...@@ -57,6 +57,7 @@ func Init() (*sys.Arch, ld.Arch) { ...@@ -57,6 +57,7 @@ func Init() (*sys.Arch, ld.Arch) {
Elfsetupplt: elfsetupplt, Elfsetupplt: elfsetupplt,
Gentext: gentext, Gentext: gentext,
Machoreloc1: machoreloc1, Machoreloc1: machoreloc1,
PEreloc1: pereloc1,
Linuxdynld: "/lib/ld-linux.so.3", // 2 for OABI, 3 for EABI Linuxdynld: "/lib/ld-linux.so.3", // 2 for OABI, 3 for EABI
Freebsddynld: "/usr/libexec/ld-elf.so.1", Freebsddynld: "/usr/libexec/ld-elf.so.1",
...@@ -130,6 +131,10 @@ func archinit(ctxt *ld.Link) { ...@@ -130,6 +131,10 @@ func archinit(ctxt *ld.Link) {
if *ld.FlagRound == -1 { if *ld.FlagRound == -1 {
*ld.FlagRound = 4096 *ld.FlagRound = 4096
} }
case objabi.Hwindows: /* PE executable */
// ld.HEADR, ld.FlagTextAddr, ld.FlagDataAddr and ld.FlagRound are set in ld.Peinit
return
} }
if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 { if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 {
......
...@@ -60,7 +60,7 @@ func (mode *BuildMode) Set(s string) error { ...@@ -60,7 +60,7 @@ func (mode *BuildMode) Set(s string) error {
} }
case "windows": case "windows":
switch objabi.GOARCH { switch objabi.GOARCH {
case "amd64", "386": case "amd64", "386", "arm":
default: default:
return badmode() return badmode()
} }
......
...@@ -539,13 +539,17 @@ func windynrelocsym(ctxt *Link, s *sym.Symbol) { ...@@ -539,13 +539,17 @@ func windynrelocsym(ctxt *Link, s *sym.Symbol) {
r.Add = int64(targ.Plt) r.Add = int64(targ.Plt)
// jmp *addr // jmp *addr
if ctxt.Arch.Family == sys.I386 { switch ctxt.Arch.Family {
default:
Errorf(s, "unsupported arch %v", ctxt.Arch.Family)
return
case sys.I386:
rel.AddUint8(0xff) rel.AddUint8(0xff)
rel.AddUint8(0x25) rel.AddUint8(0x25)
rel.AddAddr(ctxt.Arch, targ) rel.AddAddr(ctxt.Arch, targ)
rel.AddUint8(0x90) rel.AddUint8(0x90)
rel.AddUint8(0x90) rel.AddUint8(0x90)
} else { case sys.AMD64:
rel.AddUint8(0xff) rel.AddUint8(0xff)
rel.AddUint8(0x24) rel.AddUint8(0x24)
rel.AddUint8(0x25) rel.AddUint8(0x25)
......
This diff is collapsed.
...@@ -101,6 +101,19 @@ const ( ...@@ -101,6 +101,19 @@ const (
IMAGE_REL_AMD64_SREL32 = 0x000E IMAGE_REL_AMD64_SREL32 = 0x000E
IMAGE_REL_AMD64_PAIR = 0x000F IMAGE_REL_AMD64_PAIR = 0x000F
IMAGE_REL_AMD64_SSPAN32 = 0x0010 IMAGE_REL_AMD64_SSPAN32 = 0x0010
IMAGE_REL_ARM_ABSOLUTE = 0x0000
IMAGE_REL_ARM_ADDR32 = 0x0001
IMAGE_REL_ARM_ADDR32NB = 0x0002
IMAGE_REL_ARM_BRANCH24 = 0x0003
IMAGE_REL_ARM_BRANCH11 = 0x0004
IMAGE_REL_ARM_SECTION = 0x000E
IMAGE_REL_ARM_SECREL = 0x000F
IMAGE_REL_ARM_MOV32 = 0x0010
IMAGE_REL_THUMB_MOV32 = 0x0011
IMAGE_REL_THUMB_BRANCH20 = 0x0012
IMAGE_REL_THUMB_BRANCH24 = 0x0014
IMAGE_REL_THUMB_BLX23 = 0x0015
IMAGE_REL_ARM_PAIR = 0x0016
) )
// TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld, ideally in debug/pe. // TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld, ideally in debug/pe.
...@@ -241,30 +254,56 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng ...@@ -241,30 +254,56 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng
rp.Sym = gosym rp.Sym = gosym
rp.Siz = 4 rp.Siz = 4
rp.Off = int32(r.VirtualAddress) rp.Off = int32(r.VirtualAddress)
switch r.Type { switch arch.Family {
default: default:
return nil, nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type) return nil, nil, fmt.Errorf("%s: unsupported arch %v", pn, arch.Family)
case sys.I386, sys.AMD64:
switch r.Type {
default:
return nil, nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type)
case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32, case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32,
IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32 IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
IMAGE_REL_AMD64_ADDR32NB: IMAGE_REL_AMD64_ADDR32NB:
rp.Type = objabi.R_PCREL rp.Type = objabi.R_PCREL
rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:]))) rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32: case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32:
rp.Type = objabi.R_ADDR rp.Type = objabi.R_ADDR
// load addend from image // load addend from image
rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:]))) rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64 case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
rp.Siz = 8 rp.Siz = 8
rp.Type = objabi.R_ADDR rp.Type = objabi.R_ADDR
// load addend from image // load addend from image
rp.Add = int64(binary.LittleEndian.Uint64(sectdata[rsect][rp.Off:])) rp.Add = int64(binary.LittleEndian.Uint64(sectdata[rsect][rp.Off:]))
}
case sys.ARM:
switch r.Type {
default:
return nil, nil, fmt.Errorf("%s: %v: unknown ARM relocation type %v", pn, sectsyms[rsect], r.Type)
case IMAGE_REL_ARM_SECREL:
rp.Type = objabi.R_PCREL
rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
case IMAGE_REL_ARM_ADDR32:
rp.Type = objabi.R_ADDR
rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
case IMAGE_REL_ARM_BRANCH24:
rp.Type = objabi.R_CALLARM
rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:])))
}
} }
// ld -r could generate multiple section symbols for the // ld -r could generate multiple section symbols for the
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment