mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/link: plugin support on darwin/amd64
This CL turns some special section marker symbols into real symbols laid out in the sections they mark. This is to deal with the fact that dyld on OS X resolves the section marker symbols in any dlopen-ed Go program to the original section marker symbols in the host program. More details in a comment in cmd/link/internal/ld/data.go. Change-Id: Ie9451cfbf06d0bdcccb9959219c791b829f3f771 Reviewed-on: https://go-review.googlesource.com/29394 Reviewed-by: Ian Lance Taylor <iant@golang.org> Run-TryBot: David Crawshaw <crawshaw@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
26a6131bac
commit
73e7a569b4
5 changed files with 127 additions and 15 deletions
|
|
@ -88,6 +88,12 @@ func (mode *BuildMode) Set(s string) error {
|
||||||
default:
|
default:
|
||||||
return badmode()
|
return badmode()
|
||||||
}
|
}
|
||||||
|
case "darwin":
|
||||||
|
switch obj.GOARCH {
|
||||||
|
case "amd64":
|
||||||
|
default:
|
||||||
|
return badmode()
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return badmode()
|
return badmode()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1148,6 +1148,13 @@ func (p *GCProg) AddSym(s *Symbol) {
|
||||||
// Things without pointers should be in SNOPTRDATA or SNOPTRBSS;
|
// Things without pointers should be in SNOPTRDATA or SNOPTRBSS;
|
||||||
// everything we see should have pointers and should therefore have a type.
|
// everything we see should have pointers and should therefore have a type.
|
||||||
if typ == nil {
|
if typ == nil {
|
||||||
|
switch s.Name {
|
||||||
|
case "runtime.data", "runtime.edata", "runtime.bss", "runtime.ebss":
|
||||||
|
// Ignore special symbols that are sometimes laid out
|
||||||
|
// as real symbols. See comment about dyld on darwin in
|
||||||
|
// the address function.
|
||||||
|
return
|
||||||
|
}
|
||||||
Errorf(s, "missing Go type information for global symbol: size %d", s.Size)
|
Errorf(s, "missing Go type information for global symbol: size %d", s.Size)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -1213,6 +1220,46 @@ func (ctxt *Link) dodata() {
|
||||||
ctxt.Logf("%5.2f dodata\n", obj.Cputime())
|
ctxt.Logf("%5.2f dodata\n", obj.Cputime())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ctxt.DynlinkingGo() && Headtype == obj.Hdarwin {
|
||||||
|
// The values in moduledata are filled out by relocations
|
||||||
|
// pointing to the addresses of these special symbols.
|
||||||
|
// Typically these symbols have no size and are not laid
|
||||||
|
// out with their matching section.
|
||||||
|
//
|
||||||
|
// However on darwin, dyld will find the special symbol
|
||||||
|
// in the first loaded module, even though it is local.
|
||||||
|
//
|
||||||
|
// (An hypothesis, formed without looking in the dyld sources:
|
||||||
|
// these special symbols have no size, so their address
|
||||||
|
// matches a real symbol. The dynamic linker assumes we
|
||||||
|
// want the normal symbol with the same address and finds
|
||||||
|
// it in the other module.)
|
||||||
|
//
|
||||||
|
// To work around this we lay out the symbls whose
|
||||||
|
// addresses are vital for multi-module programs to work
|
||||||
|
// as normal symbols, and give them a little size.
|
||||||
|
bss := ctxt.Syms.Lookup("runtime.bss", 0)
|
||||||
|
bss.Size = 8
|
||||||
|
bss.Attr.Set(AttrSpecial, false)
|
||||||
|
|
||||||
|
ctxt.Syms.Lookup("runtime.ebss", 0).Attr.Set(AttrSpecial, false)
|
||||||
|
|
||||||
|
data := ctxt.Syms.Lookup("runtime.data", 0)
|
||||||
|
data.Size = 8
|
||||||
|
data.Attr.Set(AttrSpecial, false)
|
||||||
|
|
||||||
|
ctxt.Syms.Lookup("runtime.edata", 0).Attr.Set(AttrSpecial, false)
|
||||||
|
|
||||||
|
types := ctxt.Syms.Lookup("runtime.types", 0)
|
||||||
|
types.Type = obj.STYPE
|
||||||
|
types.Size = 8
|
||||||
|
types.Attr.Set(AttrSpecial, false)
|
||||||
|
|
||||||
|
etypes := ctxt.Syms.Lookup("runtime.etypes", 0)
|
||||||
|
etypes.Type = obj.SFUNCTAB
|
||||||
|
etypes.Attr.Set(AttrSpecial, false)
|
||||||
|
}
|
||||||
|
|
||||||
// Collect data symbols by type into data.
|
// Collect data symbols by type into data.
|
||||||
var data [obj.SXREF][]*Symbol
|
var data [obj.SXREF][]*Symbol
|
||||||
for _, s := range ctxt.Syms.Allsym {
|
for _, s := range ctxt.Syms.Allsym {
|
||||||
|
|
@ -1779,8 +1826,9 @@ func dodataSect(ctxt *Link, symn obj.SymKind, syms []*Symbol) (result []*Symbol,
|
||||||
syms = newSyms
|
syms = newSyms
|
||||||
}
|
}
|
||||||
|
|
||||||
symsSort := make([]dataSortKey, len(syms))
|
var head, tail *Symbol
|
||||||
for i, s := range syms {
|
symsSort := make([]dataSortKey, 0, len(syms))
|
||||||
|
for _, s := range syms {
|
||||||
if s.Attr.OnList() {
|
if s.Attr.OnList() {
|
||||||
log.Fatalf("symbol %s listed multiple times", s.Name)
|
log.Fatalf("symbol %s listed multiple times", s.Name)
|
||||||
}
|
}
|
||||||
|
|
@ -1794,7 +1842,21 @@ func dodataSect(ctxt *Link, symn obj.SymKind, syms []*Symbol) (result []*Symbol,
|
||||||
Errorf(s, "symbol too large (%d bytes)", s.Size)
|
Errorf(s, "symbol too large (%d bytes)", s.Size)
|
||||||
}
|
}
|
||||||
|
|
||||||
symsSort[i] = dataSortKey{
|
// If the usually-special section-marker symbols are being laid
|
||||||
|
// out as regular symbols, put them either at the beginning or
|
||||||
|
// end of their section.
|
||||||
|
if ctxt.DynlinkingGo() && Headtype == obj.Hdarwin {
|
||||||
|
switch s.Name {
|
||||||
|
case "runtime.text", "runtime.bss", "runtime.data", "runtime.types":
|
||||||
|
head = s
|
||||||
|
continue
|
||||||
|
case "runtime.etext", "runtime.ebss", "runtime.edata", "runtime.etypes":
|
||||||
|
tail = s
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key := dataSortKey{
|
||||||
size: s.Size,
|
size: s.Size,
|
||||||
name: s.Name,
|
name: s.Name,
|
||||||
sym: s,
|
sym: s,
|
||||||
|
|
@ -1806,23 +1868,33 @@ func dodataSect(ctxt *Link, symn obj.SymKind, syms []*Symbol) (result []*Symbol,
|
||||||
// from input files. Both are type SELFGOT, so in that case
|
// from input files. Both are type SELFGOT, so in that case
|
||||||
// we skip size comparison and fall through to the name
|
// we skip size comparison and fall through to the name
|
||||||
// comparison (conveniently, .got sorts before .toc).
|
// comparison (conveniently, .got sorts before .toc).
|
||||||
symsSort[i].size = 0
|
key.size = 0
|
||||||
case obj.STYPELINK:
|
case obj.STYPELINK:
|
||||||
// Sort typelinks by the rtype.string field so the reflect
|
// Sort typelinks by the rtype.string field so the reflect
|
||||||
// package can binary search type links.
|
// package can binary search type links.
|
||||||
symsSort[i].name = string(decodetypeStr(s.R[0].Sym))
|
key.name = string(decodetypeStr(s.R[0].Sym))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
symsSort = append(symsSort, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(bySizeAndName(symsSort))
|
sort.Sort(bySizeAndName(symsSort))
|
||||||
|
|
||||||
|
off := 0
|
||||||
|
if head != nil {
|
||||||
|
syms[0] = head
|
||||||
|
off++
|
||||||
|
}
|
||||||
for i, symSort := range symsSort {
|
for i, symSort := range symsSort {
|
||||||
syms[i] = symSort.sym
|
syms[i+off] = symSort.sym
|
||||||
align := symalign(symSort.sym)
|
align := symalign(symSort.sym)
|
||||||
if maxAlign < align {
|
if maxAlign < align {
|
||||||
maxAlign = align
|
maxAlign = align
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if tail != nil {
|
||||||
|
syms[len(syms)-1] = tail
|
||||||
|
}
|
||||||
|
|
||||||
if Iself && symn == obj.SELFROSECT {
|
if Iself && symn == obj.SELFROSECT {
|
||||||
// Make .rela and .rela.plt contiguous, the ELF ABI requires this
|
// Make .rela and .rela.plt contiguous, the ELF ABI requires this
|
||||||
|
|
@ -1859,7 +1931,7 @@ func dodataSect(ctxt *Link, symn obj.SymKind, syms []*Symbol) (result []*Symbol,
|
||||||
// at the very beginning of the text segment.
|
// at the very beginning of the text segment.
|
||||||
// This ``header'' is read by cmd/go.
|
// This ``header'' is read by cmd/go.
|
||||||
func (ctxt *Link) textbuildid() {
|
func (ctxt *Link) textbuildid() {
|
||||||
if Iself || *flagBuildid == "" {
|
if Iself || Buildmode == BuildmodePlugin || *flagBuildid == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1887,7 +1959,19 @@ func (ctxt *Link) textaddress() {
|
||||||
sect := Segtext.Sect
|
sect := Segtext.Sect
|
||||||
|
|
||||||
sect.Align = int32(Funcalign)
|
sect.Align = int32(Funcalign)
|
||||||
ctxt.Syms.Lookup("runtime.text", 0).Sect = sect
|
|
||||||
|
text := ctxt.Syms.Lookup("runtime.text", 0)
|
||||||
|
text.Sect = sect
|
||||||
|
|
||||||
|
if ctxt.DynlinkingGo() && Headtype == obj.Hdarwin {
|
||||||
|
etext := ctxt.Syms.Lookup("runtime.etext", 0)
|
||||||
|
etext.Sect = sect
|
||||||
|
|
||||||
|
ctxt.Textp = append(ctxt.Textp, etext, nil)
|
||||||
|
copy(ctxt.Textp[1:], ctxt.Textp)
|
||||||
|
ctxt.Textp[0] = text
|
||||||
|
}
|
||||||
|
|
||||||
if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
|
if Headtype == obj.Hwindows || Headtype == obj.Hwindowsgui {
|
||||||
ctxt.Syms.Lookup(".text", 0).Sect = sect
|
ctxt.Syms.Lookup(".text", 0).Sect = sect
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -940,6 +940,9 @@ func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
|
||||||
lang := dwarf.DW_LANG_Go
|
lang := dwarf.DW_LANG_Go
|
||||||
|
|
||||||
s := ctxt.Textp[0]
|
s := ctxt.Textp[0]
|
||||||
|
if ctxt.DynlinkingGo() && Headtype == obj.Hdarwin {
|
||||||
|
s = ctxt.Textp[1] // skip runtime.text
|
||||||
|
}
|
||||||
|
|
||||||
dwinfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, "go", 0)
|
dwinfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, "go", 0)
|
||||||
newattr(dwinfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(lang), 0)
|
newattr(dwinfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(lang), 0)
|
||||||
|
|
|
||||||
|
|
@ -954,7 +954,12 @@ func (l *Link) hostlink() {
|
||||||
|
|
||||||
switch Headtype {
|
switch Headtype {
|
||||||
case obj.Hdarwin:
|
case obj.Hdarwin:
|
||||||
argv = append(argv, "-Wl,-no_pie,-headerpad,1144")
|
argv = append(argv, "-Wl,-headerpad,1144")
|
||||||
|
if l.DynlinkingGo() {
|
||||||
|
argv = append(argv, "-Wl,-flat_namespace")
|
||||||
|
} else {
|
||||||
|
argv = append(argv, "-Wl,-no_pie")
|
||||||
|
}
|
||||||
case obj.Hopenbsd:
|
case obj.Hopenbsd:
|
||||||
argv = append(argv, "-Wl,-nopie")
|
argv = append(argv, "-Wl,-nopie")
|
||||||
case obj.Hwindows:
|
case obj.Hwindows:
|
||||||
|
|
@ -986,11 +991,20 @@ func (l *Link) hostlink() {
|
||||||
// non-closeable: a dlclose will do nothing.
|
// non-closeable: a dlclose will do nothing.
|
||||||
argv = append(argv, "-shared", "-Wl,-z,nodelete")
|
argv = append(argv, "-shared", "-Wl,-z,nodelete")
|
||||||
}
|
}
|
||||||
case BuildmodeShared, BuildmodePlugin:
|
case BuildmodeShared:
|
||||||
if UseRelro() {
|
if UseRelro() {
|
||||||
argv = append(argv, "-Wl,-z,relro")
|
argv = append(argv, "-Wl,-z,relro")
|
||||||
}
|
}
|
||||||
argv = append(argv, "-shared")
|
argv = append(argv, "-shared")
|
||||||
|
case BuildmodePlugin:
|
||||||
|
if Headtype == obj.Hdarwin {
|
||||||
|
argv = append(argv, "-dynamiclib")
|
||||||
|
} else {
|
||||||
|
if UseRelro() {
|
||||||
|
argv = append(argv, "-Wl,-z,relro")
|
||||||
|
}
|
||||||
|
argv = append(argv, "-shared")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if Iself && l.DynlinkingGo() {
|
if Iself && l.DynlinkingGo() {
|
||||||
|
|
|
||||||
|
|
@ -352,8 +352,8 @@ func machoshbits(ctxt *Link, mseg *MachoSeg, sect *Section, segname string) {
|
||||||
|
|
||||||
var msect *MachoSect
|
var msect *MachoSect
|
||||||
if sect.Rwx&1 == 0 && segname != "__DWARF" && (SysArch.Family == sys.ARM64 ||
|
if sect.Rwx&1 == 0 && segname != "__DWARF" && (SysArch.Family == sys.ARM64 ||
|
||||||
(SysArch.Family == sys.AMD64 && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive)) ||
|
(SysArch.Family == sys.AMD64 && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive || Buildmode == BuildmodePlugin)) ||
|
||||||
(SysArch.Family == sys.ARM && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive))) {
|
(SysArch.Family == sys.ARM && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive || Buildmode == BuildmodePlugin))) {
|
||||||
// Darwin external linker on arm64 and on amd64 and arm in c-shared/c-archive buildmode
|
// Darwin external linker on arm64 and on amd64 and arm in c-shared/c-archive buildmode
|
||||||
// complains about absolute relocs in __TEXT, so if the section is not
|
// complains about absolute relocs in __TEXT, so if the section is not
|
||||||
// executable, put it in __DATA segment.
|
// executable, put it in __DATA segment.
|
||||||
|
|
@ -692,8 +692,13 @@ func machosymtab(ctxt *Link) {
|
||||||
s := sortsym[i]
|
s := sortsym[i]
|
||||||
Adduint32(ctxt, symtab, uint32(symstr.Size))
|
Adduint32(ctxt, symtab, uint32(symstr.Size))
|
||||||
|
|
||||||
// Only add _ to C symbols. Go symbols have dot in the name.
|
// In normal buildmodes, only add _ to C symbols, as
|
||||||
if !strings.Contains(s.Extname, ".") {
|
// Go symbols have dot in the name.
|
||||||
|
//
|
||||||
|
// When dynamically linking, prefix all non-local
|
||||||
|
// symbols with _ as dlsym on darwin requires it to
|
||||||
|
// resolve any symbol.
|
||||||
|
if !strings.Contains(s.Extname, ".") || (ctxt.DynlinkingGo() && !s.Attr.Local()) {
|
||||||
Adduint8(ctxt, symstr, '_')
|
Adduint8(ctxt, symstr, '_')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -706,7 +711,7 @@ func machosymtab(ctxt *Link) {
|
||||||
Adduint16(ctxt, symtab, 0) // desc
|
Adduint16(ctxt, symtab, 0) // desc
|
||||||
adduintxx(ctxt, symtab, 0, SysArch.PtrSize) // no value
|
adduintxx(ctxt, symtab, 0, SysArch.PtrSize) // no value
|
||||||
} else {
|
} else {
|
||||||
if s.Attr.CgoExport() {
|
if s.Attr.CgoExport() || (ctxt.DynlinkingGo() && !s.Attr.Local()) {
|
||||||
Adduint8(ctxt, symtab, 0x0f)
|
Adduint8(ctxt, symtab, 0x0f)
|
||||||
} else {
|
} else {
|
||||||
Adduint8(ctxt, symtab, 0x0e)
|
Adduint8(ctxt, symtab, 0x0e)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue