]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/ld, cmd/8l: external linking for windows/386
authorShenghou Ma <minux@golang.org>
Mon, 9 Mar 2015 07:05:40 +0000 (03:05 -0400)
committerMinux Ma <minux@golang.org>
Tue, 24 Mar 2015 03:23:16 +0000 (03:23 +0000)
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>
src/cmd/8l/asm.go
src/cmd/8l/obj.go
src/cmd/internal/ld/data.go
src/cmd/internal/ld/go.go
src/cmd/internal/ld/lib.go
src/cmd/internal/ld/pe.go

index 59543fdb1a6b2e7d5cd521accdaf8ed177e58261..49ff0808ae64e9137677cb86cdfc491fe2781288 100644 (file)
@@ -235,6 +235,11 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) {
                        r.Type = 256 // ignore during relocsym
                        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
@@ -332,6 +337,36 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int {
        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 {
        if ld.Linkmode == ld.LinkExternal {
                return -1
index 3e0e478363a479d12221594c69123ce1f714ee8a..938a77700a3a64d44231b243c0ca2ae5e6f59469 100644 (file)
@@ -68,6 +68,7 @@ func linkarchinit() {
        ld.Thearch.Elfsetupplt = elfsetupplt
        ld.Thearch.Gentext = gentext
        ld.Thearch.Machoreloc1 = machoreloc1
+       ld.Thearch.PEreloc1 = pereloc1
        ld.Thearch.Lput = ld.Lputl
        ld.Thearch.Wput = ld.Wputl
        ld.Thearch.Vput = ld.Vputl
@@ -99,7 +100,8 @@ func archinit() {
                ld.Hfreebsd,
                ld.Hlinux,
                ld.Hnetbsd,
-               ld.Hopenbsd:
+               ld.Hopenbsd,
+               ld.Hwindows:
                break
        }
 
index 75ccfae94ba72d2cb8d341095e2ca1b5009726e2..196b13efb46b1e09be692124cf66a89327343b44 100644 (file)
@@ -443,6 +443,8 @@ func relocsym(s *LSym) {
                                        if rs.Type != SHOSTOBJ {
                                                o += Symaddr(rs)
                                        }
+                               } else if HEADTYPE == Hwindows {
+                                       // nothing to do
                                } else {
                                        Diag("unhandled pcrel relocation for %s", headstring)
                                }
@@ -497,6 +499,8 @@ func relocsym(s *LSym) {
                                        } else {
                                                o += int64(r.Siz)
                                        }
+                               } else if HEADTYPE == Hwindows {
+                                       // nothing to do
                                } else {
                                        Diag("unhandled pcrel relocation for %s", headstring)
                                }
@@ -584,7 +588,7 @@ func reloc() {
 }
 
 func dynrelocsym(s *LSym) {
-       if HEADTYPE == Hwindows {
+       if HEADTYPE == Hwindows && Linkmode != LinkExternal {
                rel := Linklookup(Ctxt, ".rel", 0)
                if s == rel {
                        return
index 1815466f305d69ee4a794f4758e4b58d99096bc2..c50e82b60d6b9c4ca98b624279f6db106b96f01f 100644 (file)
@@ -462,11 +462,6 @@ func loadcgo(file string, pkg string, p string) {
                }
 
                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 {
                                goto err
                        }
index b4f683fe9e9159659d50d58ef456aee58162a936..148ada714b4d6af8db7c4771cdb6a9d86fcb1d78 100644 (file)
@@ -99,6 +99,7 @@ type Arch struct {
        Elfsetupplt      func()
        Gentext          func()
        Machoreloc1      func(*Reloc, int64) int
+       PEreloc1         func(*Reloc, int64) bool
        Lput             func(uint32)
        Wput             func(uint16)
        Vput             func(uint64)
@@ -744,6 +745,13 @@ func hostlink() {
        if HEADTYPE == Hopenbsd {
                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)*/ {
                argv = append(argv, "-Wl,--rosegment")
@@ -844,6 +852,9 @@ func hostlink() {
                        }
                }
        }
+       if HEADTYPE == Hwindows {
+               argv = append(argv, peimporteddlls()...)
+       }
 
        if Debug['v'] != 0 {
                fmt.Fprintf(&Bso, "host link:")
@@ -1379,6 +1390,13 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
                case SFILE:
                        put(nil, s.Name, 'f', s.Value, 0, int(s.Version), nil)
                        continue
+
+               case SHOSTOBJ:
+                       if HEADTYPE == Hwindows {
+                               put(s, s.Name, 'U', s.Value, 0, int(s.Version), nil)
+                       }
+                       continue
+
                }
        }
 
index 05882867156d159a1d435396d456edf9d6b09c2b..4116f358b997ef87ae43b8e852314879110b2032 100644 (file)
@@ -114,6 +114,7 @@ const (
        IMAGE_FILE_MACHINE_AMD64             = 0x8664
        IMAGE_FILE_RELOCS_STRIPPED           = 0x0001
        IMAGE_FILE_EXECUTABLE_IMAGE          = 0x0002
+       IMAGE_FILE_LINE_NUMS_STRIPPED        = 0x0004
        IMAGE_FILE_LARGE_ADDRESS_AWARE       = 0x0020
        IMAGE_FILE_32BIT_MACHINE             = 0x0100
        IMAGE_FILE_DEBUG_STRIPPED            = 0x0200
@@ -124,6 +125,8 @@ const (
        IMAGE_SCN_MEM_READ                   = 0x40000000
        IMAGE_SCN_MEM_WRITE                  = 0x80000000
        IMAGE_SCN_MEM_DISCARDABLE            = 0x2000000
+       IMAGE_SCN_LNK_NRELOC_OVFL            = 0x1000000
+       IMAGE_SCN_ALIGN_32BYTES              = 0x600000
        IMAGE_DIRECTORY_ENTRY_EXPORT         = 0
        IMAGE_DIRECTORY_ENTRY_IMPORT         = 1
        IMAGE_DIRECTORY_ENTRY_RESOURCE       = 2
@@ -338,6 +341,8 @@ var textsect int
 
 var datasect int
 
+var bsssect int
+
 var fh IMAGE_FILE_HEADER
 
 var oh IMAGE_OPTIONAL_HEADER
@@ -374,6 +379,7 @@ type COFFSym struct {
        strtbloff int
        sect      int
        value     int64
+       typ       uint16
 }
 
 var coffsym []COFFSym
@@ -431,7 +437,7 @@ func Peinit() {
                l = binary.Size(&oh64)
                dd = oh64.DataDirectory[:]
 
-               // 32-bit architectures
+       // 32-bit architectures
        default:
                l = binary.Size(&oh)
 
@@ -451,8 +457,10 @@ func Peinit() {
 
 func pewrite() {
        Cseek(0)
-       Cwrite(dosstub)
-       strnput("PE", 4)
+       if Linkmode != LinkExternal {
+               Cwrite(dosstub)
+               strnput("PE", 4)
+       }
 
        binary.Write(&coutbuf, binary.LittleEndian, &fh)
 
@@ -517,24 +525,62 @@ func initdynimport() *Dll {
                d.ms = m
        }
 
-       dynamic := Linklookup(Ctxt, ".windynamic", 0)
-       dynamic.Reachable = true
-       dynamic.Type = SWINDOWS
-       for d := dr; d != nil; d = d.next {
-               for m = d.ms; m != nil; m = m.next {
-                       m.s.Type = SWINDOWS | SSUB
-                       m.s.Sub = dynamic.Sub
-                       dynamic.Sub = m.s
-                       m.s.Value = dynamic.Size
-                       dynamic.Size += int64(Thearch.Ptrsize)
+       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.Reachable = true
+               dynamic.Type = SWINDOWS
+               for d := dr; d != nil; d = d.next {
+                       for m = d.ms; m != nil; m = m.next {
+                               m.s.Type = SWINDOWS | SSUB
+                               m.s.Sub = dynamic.Sub
+                               dynamic.Sub = m.s
+                               m.s.Value = dynamic.Size
+                               dynamic.Size += int64(Thearch.Ptrsize)
+                       }
 
-               dynamic.Size += int64(Thearch.Ptrsize)
+                       dynamic.Size += int64(Thearch.Ptrsize)
+               }
        }
 
        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) {
        startoff := Cpos()
        dynamic := Linklookup(Ctxt, ".windynamic", 0)
@@ -738,6 +784,118 @@ func addexports() {
        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() {
        /* relocation table */
        rel := Linklookup(Ctxt, ".rel", 0)
@@ -781,7 +939,7 @@ func addpesym(s *LSym, name string, type_ int, addr int64, size int64, ver int,
                return
        }
 
-       if s.Sect == nil {
+       if s.Sect == nil && type_ != 'U' {
                return
        }
 
@@ -791,22 +949,32 @@ func addpesym(s *LSym, name string, type_ int, addr int64, size int64, ver int,
 
        case 'D',
                'B',
-               'T':
+               'T',
+               'U':
                break
        }
 
        if coffsym != nil {
+               if Linkmode == LinkExternal && (s.Type == SHOSTOBJ || s.Cgoexport != 0) && s.Name == s.Extname {
+                       s.Name = "_" + s.Name
+               }
                cs := &coffsym[ncoffsym]
                cs.sym = s
                if len(s.Name) > 8 {
                        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.sect = datasect
                } else if uint64(s.Value) >= Segtext.Vaddr {
                        cs.value = int64(uint64(s.Value) - Segtext.Vaddr)
                        cs.sect = textsect
+               } else if type_ == 'U' {
+                       cs.value = 0
+                       cs.typ = IMAGE_SYM_DTYPE_FUNCTION
                } else {
                        cs.value = 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++
 }
 
@@ -822,13 +991,26 @@ func addpesymtable() {
                genasmsym(addpesym)
                coffsym = make([]COFFSym, ncoffsym)
                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)
        }
-
        size := len(strtbl) + 4 + 18*ncoffsym
-       h := addpesection(".symtab", size, size)
-       h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
-       chksectoff(h, Cpos())
+
+       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
+               chksectoff(h, Cpos())
+       }
        fh.PointerToSymbolTable = uint32(Cpos())
        fh.NumberOfSymbols = uint32(ncoffsym)
 
@@ -845,9 +1027,15 @@ func addpesymtable() {
 
                Lputl(uint32(s.value))
                Wputl(uint16(s.sect))
-               Wputl(0x0308) // "array of structs"
-               Cput(2)       // storage class: external
-               Cput(0)       // no aux entries
+               if s.typ != 0 {
+                       Wputl(s.typ)
+               } else if Linkmode == LinkExternal {
+                       Wputl(0)
+               } else {
+                       Wputl(0x0308) // "array of structs"
+               }
+               Cput(2) // storage class: external
+               Cput(0) // no aux entries
        }
 
        // put COFF string table
@@ -856,7 +1044,9 @@ func addpesymtable() {
        for i := 0; i < len(strtbl); i++ {
                Cput(uint8(strtbl[i]))
        }
-       strnput("", int(h.SizeOfRawData-uint32(size)))
+       if Linkmode != LinkExternal {
+               strnput("", int(h.SizeOfRawData-uint32(size)))
+       }
 }
 
 func setpersrc(sym *LSym) {
@@ -921,20 +1111,38 @@ func Asmbpe() {
        chksectseg(t, &Segtext)
        textsect = pensect
 
-       d := addpesection(".data", int(Segdata.Length), int(Segdata.Filelen))
-       d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
-       chksectseg(d, &Segdata)
-       datasect = pensect
+       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
+               chksectseg(d, &Segdata)
+               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 {
                dwarfaddpeheaders()
        }
 
        Cseek(int64(nextfileoff))
-       addimports(d)
-       addexports()
+       if Linkmode != LinkExternal {
+               addimports(d)
+               addexports()
+       }
        addpesymtable()
        addpersrc()
+       if Linkmode == LinkExternal {
+               peemitreloc(t, d)
+       }
 
        fh.NumberOfSections = uint16(pensect)
 
@@ -942,7 +1150,11 @@ func Asmbpe() {
        // much more beneficial than having build timestamp in the header.
        fh.TimeDateStamp = 0
 
-       fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED
+       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
+       }
        if pe64 != 0 {
                fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
                fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE
@@ -966,8 +1178,10 @@ func Asmbpe() {
        oh.SizeOfInitializedData = d.SizeOfRawData
        oh64.SizeOfUninitializedData = 0
        oh.SizeOfUninitializedData = 0
-       oh64.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
-       oh.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
+       if Linkmode != LinkExternal {
+               oh64.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
+               oh.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
+       }
        oh64.BaseOfCode = t.VirtualAddress
        oh.BaseOfCode = t.VirtualAddress
        oh64.ImageBase = PEBASE