1
0
mirror of https://github.com/golang/go synced 2024-11-19 05:44:40 -07:00

cmd/internal/ld, cmd/8l: external linking for windows/386

Update #4069: this CL fixes the issue on windows/386.

Signed-off-by: Shenghou Ma <minux@golang.org>
Change-Id: I2d2ea233f976aab3f356f9b508cdd246d5013e2e
Reviewed-on: https://go-review.googlesource.com/7283
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Shenghou Ma 2015-03-09 03:05:40 -04:00 committed by Minux Ma
parent b6ed943bef
commit 04642e92ac
6 changed files with 309 additions and 41 deletions

View File

@ -235,6 +235,11 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
r.Type = 256 // ignore during relocsym r.Type = 256 // ignore during relocsym
return return
} }
if ld.HEADTYPE == ld.Hwindows && s.Size == PtrSize {
// nothing to do, the relocation will be laid out in pereloc1
return
}
} }
ld.Ctxt.Cursym = s ld.Ctxt.Cursym = s
@ -332,6 +337,36 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
return 0 return 0
} }
func pereloc1(r *ld.Reloc, sectoff int64) bool {
var v uint32
rs := r.Xsym
if rs.Dynid < 0 {
ld.Diag("reloc %d to non-coff symbol %s type=%d", r.Type, rs.Name, rs.Type)
return false
}
ld.Thearch.Lput(uint32(sectoff))
ld.Thearch.Lput(uint32(rs.Dynid))
switch r.Type {
default:
return false
case ld.R_ADDR:
v = ld.IMAGE_REL_I386_DIR32
case ld.R_CALL,
ld.R_PCREL:
v = ld.IMAGE_REL_I386_REL32
}
ld.Thearch.Wput(uint16(v))
return true
}
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
if ld.Linkmode == ld.LinkExternal { if ld.Linkmode == ld.LinkExternal {
return -1 return -1

View File

@ -68,6 +68,7 @@ func linkarchinit() {
ld.Thearch.Elfsetupplt = elfsetupplt ld.Thearch.Elfsetupplt = elfsetupplt
ld.Thearch.Gentext = gentext ld.Thearch.Gentext = gentext
ld.Thearch.Machoreloc1 = machoreloc1 ld.Thearch.Machoreloc1 = machoreloc1
ld.Thearch.PEreloc1 = pereloc1
ld.Thearch.Lput = ld.Lputl ld.Thearch.Lput = ld.Lputl
ld.Thearch.Wput = ld.Wputl ld.Thearch.Wput = ld.Wputl
ld.Thearch.Vput = ld.Vputl ld.Thearch.Vput = ld.Vputl
@ -99,7 +100,8 @@ func archinit() {
ld.Hfreebsd, ld.Hfreebsd,
ld.Hlinux, ld.Hlinux,
ld.Hnetbsd, ld.Hnetbsd,
ld.Hopenbsd: ld.Hopenbsd,
ld.Hwindows:
break break
} }

View File

@ -443,6 +443,8 @@ func relocsym(s *LSym) {
if rs.Type != SHOSTOBJ { if rs.Type != SHOSTOBJ {
o += Symaddr(rs) o += Symaddr(rs)
} }
} else if HEADTYPE == Hwindows {
// nothing to do
} else { } else {
Diag("unhandled pcrel relocation for %s", headstring) Diag("unhandled pcrel relocation for %s", headstring)
} }
@ -497,6 +499,8 @@ func relocsym(s *LSym) {
} else { } else {
o += int64(r.Siz) o += int64(r.Siz)
} }
} else if HEADTYPE == Hwindows {
// nothing to do
} else { } else {
Diag("unhandled pcrel relocation for %s", headstring) Diag("unhandled pcrel relocation for %s", headstring)
} }
@ -584,7 +588,7 @@ func reloc() {
} }
func dynrelocsym(s *LSym) { func dynrelocsym(s *LSym) {
if HEADTYPE == Hwindows { if HEADTYPE == Hwindows && Linkmode != LinkExternal {
rel := Linklookup(Ctxt, ".rel", 0) rel := Linklookup(Ctxt, ".rel", 0)
if s == rel { if s == rel {
return return

View File

@ -462,11 +462,6 @@ func loadcgo(file string, pkg string, p string) {
} }
if f[0] == "cgo_export_static" || f[0] == "cgo_export_dynamic" { if f[0] == "cgo_export_static" || f[0] == "cgo_export_dynamic" {
// TODO: Remove once we know Windows is okay.
if f[0] == "cgo_export_static" && HEADTYPE == Hwindows {
continue
}
if len(f) < 2 || len(f) > 3 { if len(f) < 2 || len(f) > 3 {
goto err goto err
} }

View File

@ -99,6 +99,7 @@ type Arch struct {
Elfsetupplt func() Elfsetupplt func()
Gentext func() Gentext func()
Machoreloc1 func(*Reloc, int64) int Machoreloc1 func(*Reloc, int64) int
PEreloc1 func(*Reloc, int64) bool
Lput func(uint32) Lput func(uint32)
Wput func(uint16) Wput func(uint16)
Vput func(uint64) Vput func(uint64)
@ -744,6 +745,13 @@ func hostlink() {
if HEADTYPE == Hopenbsd { if HEADTYPE == Hopenbsd {
argv = append(argv, "-Wl,-nopie") argv = append(argv, "-Wl,-nopie")
} }
if HEADTYPE == Hwindows {
if headstring == "windowsgui" {
argv = append(argv, "-mwindows")
} else {
argv = append(argv, "-mconsole")
}
}
if Iself && AssumeGoldLinker != 0 /*TypeKind(100016)*/ { if Iself && AssumeGoldLinker != 0 /*TypeKind(100016)*/ {
argv = append(argv, "-Wl,--rosegment") argv = append(argv, "-Wl,--rosegment")
@ -844,6 +852,9 @@ func hostlink() {
} }
} }
} }
if HEADTYPE == Hwindows {
argv = append(argv, peimporteddlls()...)
}
if Debug['v'] != 0 { if Debug['v'] != 0 {
fmt.Fprintf(&Bso, "host link:") fmt.Fprintf(&Bso, "host link:")
@ -1379,6 +1390,13 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
case SFILE: case SFILE:
put(nil, s.Name, 'f', s.Value, 0, int(s.Version), nil) put(nil, s.Name, 'f', s.Value, 0, int(s.Version), nil)
continue continue
case SHOSTOBJ:
if HEADTYPE == Hwindows {
put(s, s.Name, 'U', s.Value, 0, int(s.Version), nil)
}
continue
} }
} }

View File

@ -114,6 +114,7 @@ const (
IMAGE_FILE_MACHINE_AMD64 = 0x8664 IMAGE_FILE_MACHINE_AMD64 = 0x8664
IMAGE_FILE_RELOCS_STRIPPED = 0x0001 IMAGE_FILE_RELOCS_STRIPPED = 0x0001
IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002 IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002
IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004
IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020 IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020
IMAGE_FILE_32BIT_MACHINE = 0x0100 IMAGE_FILE_32BIT_MACHINE = 0x0100
IMAGE_FILE_DEBUG_STRIPPED = 0x0200 IMAGE_FILE_DEBUG_STRIPPED = 0x0200
@ -124,6 +125,8 @@ const (
IMAGE_SCN_MEM_READ = 0x40000000 IMAGE_SCN_MEM_READ = 0x40000000
IMAGE_SCN_MEM_WRITE = 0x80000000 IMAGE_SCN_MEM_WRITE = 0x80000000
IMAGE_SCN_MEM_DISCARDABLE = 0x2000000 IMAGE_SCN_MEM_DISCARDABLE = 0x2000000
IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000
IMAGE_SCN_ALIGN_32BYTES = 0x600000
IMAGE_DIRECTORY_ENTRY_EXPORT = 0 IMAGE_DIRECTORY_ENTRY_EXPORT = 0
IMAGE_DIRECTORY_ENTRY_IMPORT = 1 IMAGE_DIRECTORY_ENTRY_IMPORT = 1
IMAGE_DIRECTORY_ENTRY_RESOURCE = 2 IMAGE_DIRECTORY_ENTRY_RESOURCE = 2
@ -338,6 +341,8 @@ var textsect int
var datasect int var datasect int
var bsssect int
var fh IMAGE_FILE_HEADER var fh IMAGE_FILE_HEADER
var oh IMAGE_OPTIONAL_HEADER var oh IMAGE_OPTIONAL_HEADER
@ -374,6 +379,7 @@ type COFFSym struct {
strtbloff int strtbloff int
sect int sect int
value int64 value int64
typ uint16
} }
var coffsym []COFFSym var coffsym []COFFSym
@ -451,8 +457,10 @@ func Peinit() {
func pewrite() { func pewrite() {
Cseek(0) Cseek(0)
if Linkmode != LinkExternal {
Cwrite(dosstub) Cwrite(dosstub)
strnput("PE", 4) strnput("PE", 4)
}
binary.Write(&coutbuf, binary.LittleEndian, &fh) binary.Write(&coutbuf, binary.LittleEndian, &fh)
@ -517,6 +525,31 @@ func initdynimport() *Dll {
d.ms = m d.ms = m
} }
if Linkmode == LinkExternal {
// Add real symbol name
for d := dr; d != nil; d = d.next {
for m = d.ms; m != nil; m = m.next {
m.s.Type = SDATA
Symgrow(Ctxt, m.s, int64(Thearch.Ptrsize))
dynName := m.s.Extname
if m.argsize >= 0 {
dynName += fmt.Sprintf("@%d", m.argsize)
}
dynSym := Linklookup(Ctxt, dynName, 0)
dynSym.Reachable = true
dynSym.Type = SHOSTOBJ
r := Addrel(m.s)
r.Sym = dynSym
r.Off = 0
r.Siz = uint8(Thearch.Ptrsize)
r.Type = R_ADDR
// pre-allocate symtab entries for those symbols
dynSym.Dynid = int32(ncoffsym)
ncoffsym++
}
}
} else {
dynamic := Linklookup(Ctxt, ".windynamic", 0) dynamic := Linklookup(Ctxt, ".windynamic", 0)
dynamic.Reachable = true dynamic.Reachable = true
dynamic.Type = SWINDOWS dynamic.Type = SWINDOWS
@ -531,10 +564,23 @@ func initdynimport() *Dll {
dynamic.Size += int64(Thearch.Ptrsize) dynamic.Size += int64(Thearch.Ptrsize)
} }
}
return dr return dr
} }
// peimporteddlls returns the gcc command line argument to link all imported
// DLLs.
func peimporteddlls() []string {
var dlls []string
for d := dr; d != nil; d = d.next {
dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll"))
}
return dlls
}
func addimports(datsect *IMAGE_SECTION_HEADER) { func addimports(datsect *IMAGE_SECTION_HEADER) {
startoff := Cpos() startoff := Cpos()
dynamic := Linklookup(Ctxt, ".windynamic", 0) dynamic := Linklookup(Ctxt, ".windynamic", 0)
@ -738,6 +784,118 @@ func addexports() {
strnput("", int(sect.SizeOfRawData-uint32(size))) strnput("", int(sect.SizeOfRawData-uint32(size)))
} }
// perelocsect relocates symbols from first in section sect, and returns
// the total number of relocations emitted.
func perelocsect(sect *Section, first *LSym) int {
// If main section has no bits, nothing to relocate.
if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
return 0
}
relocs := 0
sect.Reloff = uint64(Cpos())
var sym *LSym
for sym = first; sym != nil; sym = sym.Next {
if !sym.Reachable {
continue
}
if uint64(sym.Value) >= sect.Vaddr {
break
}
}
eaddr := int32(sect.Vaddr + sect.Length)
var r *Reloc
var ri int
for ; sym != nil; sym = sym.Next {
if !sym.Reachable {
continue
}
if sym.Value >= int64(eaddr) {
break
}
Ctxt.Cursym = sym
for ri = 0; ri < len(sym.R); ri++ {
r = &sym.R[ri]
if r.Done != 0 {
continue
}
if r.Xsym == nil {
Diag("missing xsym in relocation")
continue
}
if r.Xsym.Dynid < 0 {
Diag("reloc %d to non-coff symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
}
if !Thearch.PEreloc1(r, int64(uint64(sym.Value+int64(r.Off))-PEBASE)) {
Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
}
relocs++
}
}
sect.Rellen = uint64(Cpos()) - sect.Reloff
return relocs
}
// peemitreloc emits relocation entries for go.o in external linking.
func peemitreloc(text, data *IMAGE_SECTION_HEADER) {
for Cpos()&7 != 0 {
Cput(0)
}
text.PointerToRelocations = uint32(Cpos())
// first entry: extended relocs
Lputl(0) // placeholder for number of relocation + 1
Lputl(0)
Wputl(0)
n := perelocsect(Segtext.Sect, Ctxt.Textp) + 1
for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
n += perelocsect(sect, datap)
}
cpos := Cpos()
Cseek(int64(text.PointerToRelocations))
Lputl(uint32(n))
Cseek(cpos)
if n > 0x10000 {
n = 0x10000
text.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
} else {
text.PointerToRelocations += 10 // skip the extend reloc entry
}
text.NumberOfRelocations = uint16(n - 1)
data.PointerToRelocations = uint32(cpos)
// first entry: extended relocs
Lputl(0) // placeholder for number of relocation + 1
Lputl(0)
Wputl(0)
n = 1
for sect := Segdata.Sect; sect != nil; sect = sect.Next {
n += perelocsect(sect, datap)
}
cpos = Cpos()
Cseek(int64(data.PointerToRelocations))
Lputl(uint32(n))
Cseek(cpos)
if n > 0x10000 {
n = 0x10000
data.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
} else {
data.PointerToRelocations += 10 // skip the extend reloc entry
}
data.NumberOfRelocations = uint16(n - 1)
}
func dope() { func dope() {
/* relocation table */ /* relocation table */
rel := Linklookup(Ctxt, ".rel", 0) rel := Linklookup(Ctxt, ".rel", 0)
@ -781,7 +939,7 @@ func addpesym(s *LSym, name string, type_ int, addr int64, size int64, ver int,
return return
} }
if s.Sect == nil { if s.Sect == nil && type_ != 'U' {
return return
} }
@ -791,22 +949,32 @@ func addpesym(s *LSym, name string, type_ int, addr int64, size int64, ver int,
case 'D', case 'D',
'B', 'B',
'T': 'T',
'U':
break break
} }
if coffsym != nil { if coffsym != nil {
if Linkmode == LinkExternal && (s.Type == SHOSTOBJ || s.Cgoexport != 0) && s.Name == s.Extname {
s.Name = "_" + s.Name
}
cs := &coffsym[ncoffsym] cs := &coffsym[ncoffsym]
cs.sym = s cs.sym = s
if len(s.Name) > 8 { if len(s.Name) > 8 {
cs.strtbloff = strtbladd(s.Name) cs.strtbloff = strtbladd(s.Name)
} }
if uint64(s.Value) >= Segdata.Vaddr { if uint64(s.Value) >= Segdata.Vaddr+Segdata.Filelen && Linkmode == LinkExternal {
cs.value = int64(uint64(s.Value) - Segdata.Vaddr - Segdata.Filelen)
cs.sect = bsssect
} else if uint64(s.Value) >= Segdata.Vaddr {
cs.value = int64(uint64(s.Value) - Segdata.Vaddr) cs.value = int64(uint64(s.Value) - Segdata.Vaddr)
cs.sect = datasect cs.sect = datasect
} else if uint64(s.Value) >= Segtext.Vaddr { } else if uint64(s.Value) >= Segtext.Vaddr {
cs.value = int64(uint64(s.Value) - Segtext.Vaddr) cs.value = int64(uint64(s.Value) - Segtext.Vaddr)
cs.sect = textsect cs.sect = textsect
} else if type_ == 'U' {
cs.value = 0
cs.typ = IMAGE_SYM_DTYPE_FUNCTION
} else { } else {
cs.value = 0 cs.value = 0
cs.sect = 0 cs.sect = 0
@ -814,6 +982,7 @@ func addpesym(s *LSym, name string, type_ int, addr int64, size int64, ver int,
} }
} }
s.Dynid = int32(ncoffsym)
ncoffsym++ ncoffsym++
} }
@ -822,13 +991,26 @@ func addpesymtable() {
genasmsym(addpesym) genasmsym(addpesym)
coffsym = make([]COFFSym, ncoffsym) coffsym = make([]COFFSym, ncoffsym)
ncoffsym = 0 ncoffsym = 0
if Linkmode == LinkExternal {
for d := dr; d != nil; d = d.next {
for m := d.ms; m != nil; m = m.next {
s := m.s.R[0].Xsym
addpesym(s, s.Name, 'U', 0, int64(Thearch.Ptrsize), 0, nil)
}
}
}
genasmsym(addpesym) genasmsym(addpesym)
} }
size := len(strtbl) + 4 + 18*ncoffsym size := len(strtbl) + 4 + 18*ncoffsym
h := addpesection(".symtab", size, size)
var h *IMAGE_SECTION_HEADER
if Linkmode != LinkExternal {
// We do not really need .symtab for go.o, and if we have one, ld
// will also include it in the exe, and that will confuse windows.
h = addpesection(".symtab", size, size)
h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
chksectoff(h, Cpos()) chksectoff(h, Cpos())
}
fh.PointerToSymbolTable = uint32(Cpos()) fh.PointerToSymbolTable = uint32(Cpos())
fh.NumberOfSymbols = uint32(ncoffsym) fh.NumberOfSymbols = uint32(ncoffsym)
@ -845,7 +1027,13 @@ func addpesymtable() {
Lputl(uint32(s.value)) Lputl(uint32(s.value))
Wputl(uint16(s.sect)) Wputl(uint16(s.sect))
if s.typ != 0 {
Wputl(s.typ)
} else if Linkmode == LinkExternal {
Wputl(0)
} else {
Wputl(0x0308) // "array of structs" Wputl(0x0308) // "array of structs"
}
Cput(2) // storage class: external Cput(2) // storage class: external
Cput(0) // no aux entries Cput(0) // no aux entries
} }
@ -856,7 +1044,9 @@ func addpesymtable() {
for i := 0; i < len(strtbl); i++ { for i := 0; i < len(strtbl); i++ {
Cput(uint8(strtbl[i])) Cput(uint8(strtbl[i]))
} }
if Linkmode != LinkExternal {
strnput("", int(h.SizeOfRawData-uint32(size))) strnput("", int(h.SizeOfRawData-uint32(size)))
}
} }
func setpersrc(sym *LSym) { func setpersrc(sym *LSym) {
@ -921,20 +1111,38 @@ func Asmbpe() {
chksectseg(t, &Segtext) chksectseg(t, &Segtext)
textsect = pensect textsect = pensect
d := addpesection(".data", int(Segdata.Length), int(Segdata.Filelen)) var d *IMAGE_SECTION_HEADER
if Linkmode != LinkExternal {
d = addpesection(".data", int(Segdata.Length), int(Segdata.Filelen))
d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
chksectseg(d, &Segdata) chksectseg(d, &Segdata)
datasect = pensect datasect = pensect
} else {
d = addpesection(".data", int(Segdata.Filelen), int(Segdata.Filelen))
d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
chksectseg(d, &Segdata)
datasect = pensect
b := addpesection(".bss", int(Segdata.Length-Segdata.Filelen), 0)
b.Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
b.PointerToRawData = 0
bsssect = pensect
}
if Debug['s'] == 0 { if Debug['s'] == 0 {
dwarfaddpeheaders() dwarfaddpeheaders()
} }
Cseek(int64(nextfileoff)) Cseek(int64(nextfileoff))
if Linkmode != LinkExternal {
addimports(d) addimports(d)
addexports() addexports()
}
addpesymtable() addpesymtable()
addpersrc() addpersrc()
if Linkmode == LinkExternal {
peemitreloc(t, d)
}
fh.NumberOfSections = uint16(pensect) fh.NumberOfSections = uint16(pensect)
@ -942,7 +1150,11 @@ func Asmbpe() {
// much more beneficial than having build timestamp in the header. // much more beneficial than having build timestamp in the header.
fh.TimeDateStamp = 0 fh.TimeDateStamp = 0
if Linkmode == LinkExternal {
fh.Characteristics = IMAGE_FILE_LINE_NUMS_STRIPPED
} else {
fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED
}
if pe64 != 0 { if pe64 != 0 {
fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64)) fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE
@ -966,8 +1178,10 @@ func Asmbpe() {
oh.SizeOfInitializedData = d.SizeOfRawData oh.SizeOfInitializedData = d.SizeOfRawData
oh64.SizeOfUninitializedData = 0 oh64.SizeOfUninitializedData = 0
oh.SizeOfUninitializedData = 0 oh.SizeOfUninitializedData = 0
if Linkmode != LinkExternal {
oh64.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE) oh64.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
oh.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE) oh.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
}
oh64.BaseOfCode = t.VirtualAddress oh64.BaseOfCode = t.VirtualAddress
oh.BaseOfCode = t.VirtualAddress oh.BaseOfCode = t.VirtualAddress
oh64.ImageBase = PEBASE oh64.ImageBase = PEBASE