diff options
| author | Rick Hudson <rlh@golang.org> | 2016-04-27 18:19:16 -0400 |
|---|---|---|
| committer | Rick Hudson <rlh@golang.org> | 2016-04-27 18:46:52 -0400 |
| commit | 23aeb34df172b17b7bfaa85fb59ca64bef9073bb (patch) | |
| tree | a8ab866f1e50f0059856ce628f036d93ab620155 /src/cmd/link/internal | |
| parent | 1354b32cd70f2702381764fd595dd2faa996840c (diff) | |
| parent | d3c79d324acd7300b6f705e66af8ca711af00d9f (diff) | |
| download | go-23aeb34df172b17b7bfaa85fb59ca64bef9073bb.tar.xz | |
[dev.garbage] Merge remote-tracking branch 'origin/master' into HEAD
Change-Id: I282fd9ce9db435dfd35e882a9502ab1abc185297
Diffstat (limited to 'src/cmd/link/internal')
43 files changed, 2207 insertions, 2653 deletions
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index d809f6e8ed..cdb0354579 100644 --- a/src/cmd/link/internal/amd64/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -86,12 +86,7 @@ func gentext() { Addcall(ld.Ctxt, initfunc, addmoduledata) // c: c3 retq o(0xc3) - if ld.Ctxt.Etextp != nil { - ld.Ctxt.Etextp.Next = initfunc - } else { - ld.Ctxt.Textp = initfunc - } - ld.Ctxt.Etextp = initfunc + ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc) initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0) initarray_entry.Attr |= ld.AttrReachable initarray_entry.Attr |= ld.AttrLocal @@ -99,12 +94,6 @@ func gentext() { ld.Addaddr(ld.Ctxt, initarray_entry, initfunc) } -func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) { - ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off)) - ld.Adduint64(ld.Ctxt, rela, ld.R_X86_64_RELATIVE) - ld.Addaddrplus(ld.Ctxt, rela, r.Sym, r.Add) // Addend -} - func adddynrel(s *ld.LSym, r *ld.Reloc) { targ := r.Sym ld.Ctxt.Cursym = s @@ -285,7 +274,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { return } - if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.Thearch.Ptrsize) && r.Off == 0 { + if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.SysArch.PtrSize) && r.Off == 0 { // Mach-O relocations are a royal pain to lay out. // They use a compact stateful bytecode representation // that is too much bother to deal with. @@ -611,12 +600,12 @@ func addgotsym(s *ld.LSym) { func asmb() { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime()) } ld.Bso.Flush() if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f codeblk\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f codeblk\n", obj.Cputime()) } ld.Bso.Flush() @@ -634,7 +623,7 @@ func asmb() { if ld.Segrodata.Filelen > 0 { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) } ld.Bso.Flush() @@ -643,26 +632,18 @@ func asmb() { } if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime()) } ld.Bso.Flush() ld.Cseek(int64(ld.Segdata.Fileoff)) ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) + ld.Cseek(int64(ld.Segdwarf.Fileoff)) + ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) + machlink := int64(0) if ld.HEADTYPE == obj.Hdarwin { - if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) - } - - dwarfoff := ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)) - ld.Cseek(dwarfoff) - - ld.Segdwarf.Fileoff = uint64(ld.Cpos()) - ld.Dwarfemitdebugsections() - ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff - machlink = ld.Domacholink() } @@ -696,7 +677,7 @@ func asmb() { symo := int64(0) if ld.Debug['s'] == 0 { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime()) } ld.Bso.Flush() switch ld.HEADTYPE { @@ -715,11 +696,11 @@ func asmb() { obj.Hdragonfly, obj.Hsolaris, obj.Hnacl: - symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen) + symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) symo = ld.Rnd(symo, int64(ld.INITRND)) case obj.Hwindows: - symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen) + symo = int64(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) symo = ld.Rnd(symo, ld.PEFILEALIGN) } @@ -733,11 +714,9 @@ func asmb() { ld.Cwrite(ld.Elfstrdat) if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime()) } - ld.Dwarfemitdebugsections() - if ld.Linkmode == ld.LinkExternal { ld.Elfemitreloc() } @@ -751,7 +730,7 @@ func asmb() { if sym != nil { ld.Lcsize = int32(len(sym.P)) for i := 0; int32(i) < ld.Lcsize; i++ { - ld.Cput(uint8(sym.P[i])) + ld.Cput(sym.P[i]) } ld.Cflush() @@ -759,11 +738,9 @@ func asmb() { case obj.Hwindows: if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime()) } - ld.Dwarfemitdebugsections() - case obj.Hdarwin: if ld.Linkmode == ld.LinkExternal { ld.Machoemitreloc() @@ -772,7 +749,7 @@ func asmb() { } if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f headr\n", obj.Cputime()) } ld.Bso.Flush() ld.Cseek(0) diff --git a/src/cmd/link/internal/amd64/l.go b/src/cmd/link/internal/amd64/l.go index 4ec8610afb..2fbc8adc51 100644 --- a/src/cmd/link/internal/amd64/l.go +++ b/src/cmd/link/internal/amd64/l.go @@ -31,16 +31,11 @@ package amd64 const ( - thechar = '6' MaxAlign = 32 // max data alignment MinAlign = 1 // min data alignment FuncAlign = 16 ) -const ( - MINLC = 1 -) - /* Used by ../internal/ld/dwarf.go */ const ( DWARFREGSP = 7 diff --git a/src/cmd/link/internal/amd64/obj.go b/src/cmd/link/internal/amd64/obj.go index f9e13f2e18..860f588224 100644 --- a/src/cmd/link/internal/amd64/obj.go +++ b/src/cmd/link/internal/amd64/obj.go @@ -32,6 +32,7 @@ package amd64 import ( "cmd/internal/obj" + "cmd/internal/sys" "cmd/link/internal/ld" "fmt" "log" @@ -45,20 +46,14 @@ func Main() { } func linkarchinit() { - ld.Thestring = "amd64" - ld.Thelinkarch = &ld.Linkamd64 + ld.SysArch = sys.ArchAMD64 if obj.Getgoarch() == "amd64p32" { - ld.Thelinkarch = &ld.Linkamd64p32 + ld.SysArch = sys.ArchAMD64P32 } - ld.Thearch.Thechar = thechar - ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize - ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize - ld.Thearch.Regsize = ld.Thelinkarch.Regsize ld.Thearch.Funcalign = FuncAlign ld.Thearch.Maxalign = MaxAlign ld.Thearch.Minalign = MinAlign - ld.Thearch.Minlc = MINLC ld.Thearch.Dwarfregsp = DWARFREGSP ld.Thearch.Dwarfreglr = DWARFREGLR diff --git a/src/cmd/link/internal/amd64/z.go b/src/cmd/link/internal/amd64/z.go deleted file mode 100644 index f70035b9e3..0000000000 --- a/src/cmd/link/internal/amd64/z.go +++ /dev/null @@ -1 +0,0 @@ -package amd64 diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go index bb90cf77b6..aafdd9bc3d 100644 --- a/src/cmd/link/internal/arm/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -95,12 +95,7 @@ func gentext() { rel.Type = obj.R_PCREL rel.Add = 4 - if ld.Ctxt.Etextp != nil { - ld.Ctxt.Etextp.Next = initfunc - } else { - ld.Ctxt.Textp = initfunc - } - ld.Ctxt.Etextp = initfunc + ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc) initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0) initarray_entry.Attr |= ld.AttrReachable initarray_entry.Attr |= ld.AttrLocal @@ -114,11 +109,6 @@ func braddoff(a int32, b int32) int32 { return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b)) } -func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) { - ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off)) - ld.Adduint32(ld.Ctxt, rel, ld.R_ARM_RELATIVE) -} - func adddynrel(s *ld.LSym, r *ld.Reloc) { targ := r.Sym ld.Ctxt.Cursym = s @@ -340,6 +330,36 @@ func machoreloc1(r *ld.Reloc, sectoff int64) int { rs := r.Xsym + if r.Type == obj.R_PCREL { + if rs.Type == obj.SHOSTOBJ { + ld.Diag("pc-relative relocation of external symbol is not supported") + return -1 + } + if r.Siz != 4 { + return -1 + } + + // emit a pair of "scattered" relocations that + // resolve to the difference of section addresses of + // the symbol and the instruction + // this value is added to the field being relocated + o1 := uint32(sectoff) + o1 |= 1 << 31 // scattered bit + o1 |= ld.MACHO_ARM_RELOC_SECTDIFF << 24 + o1 |= 2 << 28 // size = 4 + + o2 := uint32(0) + o2 |= 1 << 31 // scattered bit + o2 |= ld.MACHO_ARM_RELOC_PAIR << 24 + o2 |= 2 << 28 // size = 4 + + ld.Thearch.Lput(o1) + ld.Thearch.Lput(uint32(ld.Symaddr(rs))) + ld.Thearch.Lput(o2) + ld.Thearch.Lput(uint32(ld.Ctxt.Cursym.Value + int64(r.Off))) + return 0 + } + if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_CALLARM { if rs.Dynid < 0 { ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type) @@ -563,7 +583,7 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) { func asmb() { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime()) } ld.Bso.Flush() @@ -581,7 +601,7 @@ func asmb() { if ld.Segrodata.Filelen > 0 { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) } ld.Bso.Flush() @@ -590,26 +610,18 @@ func asmb() { } if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime()) } ld.Bso.Flush() ld.Cseek(int64(ld.Segdata.Fileoff)) ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) + ld.Cseek(int64(ld.Segdwarf.Fileoff)) + ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) + machlink := uint32(0) if ld.HEADTYPE == obj.Hdarwin { - if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) - } - - dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) - ld.Cseek(int64(dwarfoff)) - - ld.Segdwarf.Fileoff = uint64(ld.Cpos()) - ld.Dwarfemitdebugsections() - ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff - machlink = uint32(ld.Domacholink()) } @@ -621,13 +633,13 @@ func asmb() { if ld.Debug['s'] == 0 { // TODO: rationalize if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime()) } ld.Bso.Flush() switch ld.HEADTYPE { default: if ld.Iself { - symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) + symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND))) } @@ -643,17 +655,12 @@ func asmb() { default: if ld.Iself { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime()) } ld.Asmelfsym() ld.Cflush() ld.Cwrite(ld.Elfstrdat) - if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) - } - ld.Dwarfemitdebugsections() - if ld.Linkmode == ld.LinkExternal { ld.Elfemitreloc() } @@ -667,7 +674,7 @@ func asmb() { if sym != nil { ld.Lcsize = int32(len(sym.P)) for i := 0; int32(i) < ld.Lcsize; i++ { - ld.Cput(uint8(sym.P[i])) + ld.Cput(sym.P[i]) } ld.Cflush() @@ -682,7 +689,7 @@ func asmb() { ld.Ctxt.Cursym = nil if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime()) } ld.Bso.Flush() ld.Cseek(0) diff --git a/src/cmd/link/internal/arm/l.go b/src/cmd/link/internal/arm/l.go index 58aecc4b64..2b73a7b172 100644 --- a/src/cmd/link/internal/arm/l.go +++ b/src/cmd/link/internal/arm/l.go @@ -63,11 +63,9 @@ package arm // THE SOFTWARE. const ( - thechar = '5' MaxAlign = 8 // max data alignment MinAlign = 1 // min data alignment FuncAlign = 4 // single-instruction alignment - MINLC = 4 ) /* Used by ../internal/ld/dwarf.go */ diff --git a/src/cmd/link/internal/arm/obj.go b/src/cmd/link/internal/arm/obj.go index bcd61fda9b..9125a1fa32 100644 --- a/src/cmd/link/internal/arm/obj.go +++ b/src/cmd/link/internal/arm/obj.go @@ -32,6 +32,7 @@ package arm import ( "cmd/internal/obj" + "cmd/internal/sys" "cmd/link/internal/ld" "fmt" "log" @@ -45,17 +46,11 @@ func Main() { } func linkarchinit() { - ld.Thestring = "arm" - ld.Thelinkarch = &ld.Linkarm + ld.SysArch = sys.ArchARM - ld.Thearch.Thechar = thechar - ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize - ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize - ld.Thearch.Regsize = ld.Thelinkarch.Regsize ld.Thearch.Funcalign = FuncAlign ld.Thearch.Maxalign = MaxAlign ld.Thearch.Minalign = MinAlign - ld.Thearch.Minlc = MINLC ld.Thearch.Dwarfregsp = DWARFREGSP ld.Thearch.Dwarfreglr = DWARFREGLR diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index 250f0afb16..97803c9d03 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -78,12 +78,7 @@ func gentext() { rel.Sym = ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0) rel.Type = obj.R_CALLARM64 // Really should be R_AARCH64_JUMP26 but doesn't seem to make any difference - if ld.Ctxt.Etextp != nil { - ld.Ctxt.Etextp.Next = initfunc - } else { - ld.Ctxt.Textp = initfunc - } - ld.Ctxt.Etextp = initfunc + ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc) initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0) initarray_entry.Attr |= ld.AttrReachable initarray_entry.Attr |= ld.AttrLocal @@ -91,10 +86,6 @@ func gentext() { ld.Addaddr(ld.Ctxt, initarray_entry, initfunc) } -func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) { - log.Fatalf("adddynrela not implemented") -} - func adddynrel(s *ld.LSym, r *ld.Reloc) { log.Fatalf("adddynrel not implemented") } @@ -375,7 +366,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { } // The TCB is two pointers. This is not documented anywhere, but is // de facto part of the ABI. - v := r.Sym.Value + int64(2*ld.Thearch.Ptrsize) + v := r.Sym.Value + int64(2*ld.SysArch.PtrSize) if v < 0 || v >= 32678 { ld.Diag("TLS offset out of range %d", v) } @@ -401,7 +392,7 @@ func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 { func asmb() { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime()) } ld.Bso.Flush() @@ -419,7 +410,7 @@ func asmb() { if ld.Segrodata.Filelen > 0 { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) } ld.Bso.Flush() @@ -428,26 +419,18 @@ func asmb() { } if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime()) } ld.Bso.Flush() ld.Cseek(int64(ld.Segdata.Fileoff)) ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) + ld.Cseek(int64(ld.Segdwarf.Fileoff)) + ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) + machlink := uint32(0) if ld.HEADTYPE == obj.Hdarwin { - if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) - } - - dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) - ld.Cseek(int64(dwarfoff)) - - ld.Segdwarf.Fileoff = uint64(ld.Cpos()) - ld.Dwarfemitdebugsections() - ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff - machlink = uint32(ld.Domacholink()) } @@ -459,13 +442,13 @@ func asmb() { if ld.Debug['s'] == 0 { // TODO: rationalize if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime()) } ld.Bso.Flush() switch ld.HEADTYPE { default: if ld.Iself { - symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) + symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND))) } @@ -481,17 +464,12 @@ func asmb() { default: if ld.Iself { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime()) } ld.Asmelfsym() ld.Cflush() ld.Cwrite(ld.Elfstrdat) - if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) - } - ld.Dwarfemitdebugsections() - if ld.Linkmode == ld.LinkExternal { ld.Elfemitreloc() } @@ -505,7 +483,7 @@ func asmb() { if sym != nil { ld.Lcsize = int32(len(sym.P)) for i := 0; int32(i) < ld.Lcsize; i++ { - ld.Cput(uint8(sym.P[i])) + ld.Cput(sym.P[i]) } ld.Cflush() @@ -520,7 +498,7 @@ func asmb() { ld.Ctxt.Cursym = nil if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime()) } ld.Bso.Flush() ld.Cseek(0) diff --git a/src/cmd/link/internal/arm64/l.go b/src/cmd/link/internal/arm64/l.go index b9b7ea50e3..67ad5c977f 100644 --- a/src/cmd/link/internal/arm64/l.go +++ b/src/cmd/link/internal/arm64/l.go @@ -62,11 +62,9 @@ package arm64 // THE SOFTWARE. const ( - thechar = '7' MaxAlign = 32 // max data alignment MinAlign = 1 // min data alignment FuncAlign = 8 - MINLC = 4 ) /* Used by ../internal/ld/dwarf.go */ diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go index 693e106ff1..1169e79a58 100644 --- a/src/cmd/link/internal/arm64/obj.go +++ b/src/cmd/link/internal/arm64/obj.go @@ -32,6 +32,7 @@ package arm64 import ( "cmd/internal/obj" + "cmd/internal/sys" "cmd/link/internal/ld" "fmt" "log" @@ -45,17 +46,11 @@ func Main() { } func linkarchinit() { - ld.Thestring = obj.Getgoarch() - ld.Thelinkarch = &ld.Linkarm64 + ld.SysArch = sys.ArchARM64 - ld.Thearch.Thechar = thechar - ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize - ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize - ld.Thearch.Regsize = ld.Thelinkarch.Regsize ld.Thearch.Funcalign = FuncAlign ld.Thearch.Maxalign = MaxAlign ld.Thearch.Minalign = MinAlign - ld.Thearch.Minlc = MINLC ld.Thearch.Dwarfregsp = DWARFREGSP ld.Thearch.Dwarfreglr = DWARFREGLR diff --git a/src/cmd/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go index d07756071d..323dfbefc5 100644 --- a/src/cmd/link/internal/ld/ar.go +++ b/src/cmd/link/internal/ld/ar.go @@ -31,9 +31,11 @@ package ld import ( + "cmd/internal/bio" "cmd/internal/obj" "encoding/binary" "fmt" + "io" "os" ) @@ -62,26 +64,26 @@ type ArHdr struct { // define them. This is used for the compiler support library // libgcc.a. func hostArchive(name string) { - f, err := obj.Bopenr(name) + f, err := bio.Open(name) if err != nil { if os.IsNotExist(err) { // It's OK if we don't have a libgcc file at all. if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "skipping libgcc file: %v\n", err) + fmt.Fprintf(Bso, "skipping libgcc file: %v\n", err) } return } Exitf("cannot open file %s: %v", name, err) } - defer obj.Bterm(f) + defer f.Close() - magbuf := make([]byte, len(ARMAG)) - if obj.Bread(f, magbuf) != len(magbuf) { + var magbuf [len(ARMAG)]byte + if _, err := io.ReadFull(f, magbuf[:]); err != nil { Exitf("file %s too short", name) } var arhdr ArHdr - l := nextar(f, obj.Boffset(f), &arhdr) + l := nextar(f, f.Offset(), &arhdr) if l <= 0 { Exitf("%s missing armap", name) } @@ -117,7 +119,7 @@ func hostArchive(name string) { l = atolwhex(arhdr.size) h := ldobj(f, "libgcc", l, pname, name, ArchiveObj) - obj.Bseek(f, h.off, 0) + f.Seek(h.off, 0) h.ld(f, h.pkg, h.length, h.pn) } @@ -130,16 +132,15 @@ func hostArchive(name string) { type archiveMap map[string]uint64 // readArmap reads the archive symbol map. -func readArmap(filename string, f *obj.Biobuf, arhdr ArHdr) archiveMap { +func readArmap(filename string, f *bio.Reader, arhdr ArHdr) archiveMap { is64 := arhdr.name == "/SYM64/" wordSize := 4 if is64 { wordSize = 8 } - l := atolwhex(arhdr.size) - contents := make([]byte, l) - if obj.Bread(f, contents) != int(l) { + contents := make([]byte, atolwhex(arhdr.size)) + if _, err := io.ReadFull(f, contents); err != nil { Exitf("short read from %s", filename) } diff --git a/src/cmd/link/internal/ld/arch.go b/src/cmd/link/internal/ld/arch.go deleted file mode 100644 index d28f37fa02..0000000000 --- a/src/cmd/link/internal/ld/arch.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ld - -import "encoding/binary" - -var Linkarm = LinkArch{ - ByteOrder: binary.LittleEndian, - Name: "arm", - Thechar: '5', - Minlc: 4, - Ptrsize: 4, - Regsize: 4, -} - -var Linkarm64 = LinkArch{ - ByteOrder: binary.LittleEndian, - Name: "arm64", - Thechar: '7', - Minlc: 4, - Ptrsize: 8, - Regsize: 8, -} - -var Linkamd64 = LinkArch{ - ByteOrder: binary.LittleEndian, - Name: "amd64", - Thechar: '6', - Minlc: 1, - Ptrsize: 8, - Regsize: 8, -} - -var Linkamd64p32 = LinkArch{ - ByteOrder: binary.LittleEndian, - Name: "amd64p32", - Thechar: '6', - Minlc: 1, - Ptrsize: 4, - Regsize: 8, -} - -var Link386 = LinkArch{ - ByteOrder: binary.LittleEndian, - Name: "386", - Thechar: '8', - Minlc: 1, - Ptrsize: 4, - Regsize: 4, -} - -var Linkppc64 = LinkArch{ - ByteOrder: binary.BigEndian, - Name: "ppc64", - Thechar: '9', - Minlc: 4, - Ptrsize: 8, - Regsize: 8, -} - -var Linkppc64le = LinkArch{ - ByteOrder: binary.LittleEndian, - Name: "ppc64le", - Thechar: '9', - Minlc: 4, - Ptrsize: 8, - Regsize: 8, -} - -var Linkmips64 = LinkArch{ - ByteOrder: binary.BigEndian, - Name: "mips64", - Thechar: '0', - Minlc: 4, - Ptrsize: 8, - Regsize: 8, -} - -var Linkmips64le = LinkArch{ - ByteOrder: binary.LittleEndian, - Name: "mips64le", - Thechar: '0', - Minlc: 4, - Ptrsize: 8, - Regsize: 8, -} - -var Links390x = LinkArch{ - ByteOrder: binary.BigEndian, - Name: "s390x", - Thechar: 'z', - Minlc: 2, - Ptrsize: 8, - Regsize: 8, -} diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index fe74cc9208..8964757846 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -34,12 +34,14 @@ package ld import ( "cmd/internal/gcprog" "cmd/internal/obj" + "cmd/internal/sys" "fmt" "log" "os" "sort" "strconv" "strings" + "sync" ) func Symgrow(ctxt *Link, s *LSym, siz int64) { @@ -49,8 +51,9 @@ func Symgrow(ctxt *Link, s *LSym, siz int64) { if int64(len(s.P)) >= siz { return } - for cap(s.P) < int(siz) { - s.P = append(s.P[:len(s.P)], 0) + if cap(s.P) < int(siz) { + p := make([]byte, 2*(siz+1)) + s.P = append(p[:0], s.P...) } s.P = s.P[:siz] } @@ -78,12 +81,23 @@ func setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 { case 4: ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(v)) case 8: - ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(v)) + ctxt.Arch.ByteOrder.PutUint64(s.P[off:], v) } return off + wid } +func Addbytes(ctxt *Link, s *LSym, bytes []byte) int64 { + if s.Type == 0 { + s.Type = obj.SDATA + } + s.Attr |= AttrReachable + s.P = append(s.P, bytes...) + s.Size = int64(len(s.P)) + + return s.Size +} + func adduintxx(ctxt *Link, s *LSym, v uint64, wid int) int64 { off := s.Size setuintxx(ctxt, s, off, v, int64(wid)) @@ -91,7 +105,15 @@ func adduintxx(ctxt *Link, s *LSym, v uint64, wid int) int64 { } func Adduint8(ctxt *Link, s *LSym, v uint8) int64 { - return adduintxx(ctxt, s, uint64(v), 1) + off := s.Size + if s.Type == 0 { + s.Type = obj.SDATA + } + s.Attr |= AttrReachable + s.Size++ + s.P = append(s.P, v) + + return off } func Adduint16(ctxt *Link, s *LSym, v uint16) int64 { @@ -107,7 +129,7 @@ func Adduint64(ctxt *Link, s *LSym, v uint64) int64 { } func adduint(ctxt *Link, s *LSym, v uint64) int64 { - return adduintxx(ctxt, s, v, Thearch.Intsize) + return adduintxx(ctxt, s, v, SysArch.IntSize) } func setuint8(ctxt *Link, s *LSym, r int64, v uint8) int64 { @@ -124,12 +146,12 @@ func Addaddrplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 { } s.Attr |= AttrReachable i := s.Size - s.Size += int64(ctxt.Arch.Ptrsize) + s.Size += int64(ctxt.Arch.PtrSize) Symgrow(ctxt, s, s.Size) r := Addrel(s) r.Sym = t r.Off = int32(i) - r.Siz = uint8(ctxt.Arch.Ptrsize) + r.Siz = uint8(ctxt.Arch.PtrSize) r.Type = obj.R_ADDR r.Add = add return i + int64(r.Siz) @@ -149,7 +171,7 @@ func Addpcrelplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 { r.Add = add r.Type = obj.R_PCREL r.Siz = 4 - if Thearch.Thechar == 'z' { + if SysArch.Family == sys.S390X { r.Variant = RV_390_DBL } return i + int64(r.Siz) @@ -164,15 +186,15 @@ func setaddrplus(ctxt *Link, s *LSym, off int64, t *LSym, add int64) int64 { s.Type = obj.SDATA } s.Attr |= AttrReachable - if off+int64(ctxt.Arch.Ptrsize) > s.Size { - s.Size = off + int64(ctxt.Arch.Ptrsize) + if off+int64(ctxt.Arch.PtrSize) > s.Size { + s.Size = off + int64(ctxt.Arch.PtrSize) Symgrow(ctxt, s, s.Size) } r := Addrel(s) r.Sym = t r.Off = int32(off) - r.Siz = uint8(ctxt.Arch.Ptrsize) + r.Siz = uint8(ctxt.Arch.PtrSize) r.Type = obj.R_ADDR r.Add = add return off + int64(r.Siz) @@ -188,12 +210,12 @@ func addsize(ctxt *Link, s *LSym, t *LSym) int64 { } s.Attr |= AttrReachable i := s.Size - s.Size += int64(ctxt.Arch.Ptrsize) + s.Size += int64(ctxt.Arch.PtrSize) Symgrow(ctxt, s, s.Size) r := Addrel(s) r.Sym = t r.Off = int32(i) - r.Siz = uint8(ctxt.Arch.Ptrsize) + r.Siz = uint8(ctxt.Arch.PtrSize) r.Type = obj.R_SIZE return i + int64(r.Siz) } @@ -221,10 +243,6 @@ func addaddrplus4(ctxt *Link, s *LSym, t *LSym, add int64) int64 { * Used for the data block. */ -func listnextp(s *LSym) **LSym { - return &s.Next -} - func listsubp(s *LSym) **LSym { return &s.Sub } @@ -342,7 +360,7 @@ func relocsym(s *LSym) { // We need to be able to reference dynimport symbols when linking against // shared libraries, and Solaris needs it always if HEADTYPE != obj.Hsolaris && r.Sym != nil && r.Sym.Type == obj.SDYNIMPORT && !DynlinkingGo() { - if !(Thearch.Thechar == '9' && Linkmode == LinkExternal && r.Sym.Name == ".TOC.") { + if !(SysArch.Family == sys.PPC64 && Linkmode == LinkExternal && r.Sym.Name == ".TOC.") { Diag("unhandled relocation for %s (type %d rtype %d)", r.Sym.Name, r.Sym.Type, r.Type) } } @@ -351,7 +369,7 @@ func relocsym(s *LSym) { } // TODO(mundaym): remove this special case - see issue 14218. - if Thearch.Thechar == 'z' { + if SysArch.Family == sys.S390X { switch r.Type { case obj.R_PCRELDBL: r.Type = obj.R_PCREL @@ -380,7 +398,7 @@ func relocsym(s *LSym) { } case obj.R_TLS_LE: - isAndroidX86 := goos == "android" && (Thearch.Thechar == '6' || Thearch.Thechar == '8') + isAndroidX86 := goos == "android" && (SysArch.InFamily(sys.AMD64, sys.I386)) if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 { r.Done = 0 @@ -390,13 +408,13 @@ func relocsym(s *LSym) { r.Xsym = r.Sym r.Xadd = r.Add o = 0 - if Thearch.Thechar != '6' { + if SysArch.Family != sys.AMD64 { o = r.Add } break } - if Iself && Thearch.Thechar == '5' { + if Iself && SysArch.Family == sys.ARM { // On ELF ARM, the thread pointer is 8 bytes before // the start of the thread-local data block, so add 8 // to the actual TLS offset (r->sym->value). @@ -414,7 +432,7 @@ func relocsym(s *LSym) { } case obj.R_TLS_IE: - isAndroidX86 := goos == "android" && (Thearch.Thechar == '6' || Thearch.Thechar == '8') + isAndroidX86 := goos == "android" && (SysArch.InFamily(sys.AMD64, sys.I386)) if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd && !isAndroidX86 { r.Done = 0 @@ -424,7 +442,7 @@ func relocsym(s *LSym) { r.Xsym = r.Sym r.Xadd = r.Add o = 0 - if Thearch.Thechar != '6' { + if SysArch.Family != sys.AMD64 { o = r.Add } break @@ -451,7 +469,7 @@ func relocsym(s *LSym) { o = r.Xadd if Iself { - if Thearch.Thechar == '6' { + if SysArch.Family == sys.AMD64 { o = 0 } } else if HEADTYPE == obj.Hdarwin { @@ -461,10 +479,10 @@ func relocsym(s *LSym) { // The workaround is that on arm64 don't ever add symaddr to o and always use // extern relocation by requiring rs->dynid >= 0. if rs.Type != obj.SHOSTOBJ { - if Thearch.Thechar == '7' && rs.Dynid < 0 { + if SysArch.Family == sys.ARM64 && rs.Dynid < 0 { Diag("R_ADDR reloc to %s+%d is not supported on darwin/arm64", rs.Name, o) } - if Thearch.Thechar != '7' { + if SysArch.Family != sys.ARM64 { o += Symaddr(rs) } } @@ -484,11 +502,33 @@ func relocsym(s *LSym) { // fail at runtime. See https://golang.org/issue/7980. // Instead of special casing only amd64, we treat this as an error on all // 64-bit architectures so as to be future-proof. - if int32(o) < 0 && Thearch.Ptrsize > 4 && siz == 4 { + if int32(o) < 0 && SysArch.PtrSize > 4 && siz == 4 { Diag("non-pc-relative relocation address is too big: %#x (%#x + %#x)", uint64(o), Symaddr(r.Sym), r.Add) errorexit() } + case obj.R_DWARFREF: + if r.Sym.Sect == nil { + Diag("missing DWARF section: %s from %s", r.Sym.Name, s.Name) + } + if Linkmode == LinkExternal { + r.Done = 0 + r.Type = obj.R_ADDR + + r.Xsym = Linkrlookup(Ctxt, r.Sym.Sect.Name, 0) + r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + o = r.Xadd + rs = r.Xsym + if Iself && SysArch.Family == sys.AMD64 { + o = 0 + } + break + } + o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr) + + case obj.R_ADDROFF: + o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add + // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call. case obj.R_CALL, obj.R_GOTPCREL, obj.R_PCREL: if Linkmode == LinkExternal && r.Sym != nil && r.Sym.Type != obj.SCONST && (r.Sym.Sect != Ctxt.Cursym.Sect || r.Type == obj.R_GOTPCREL) { @@ -511,7 +551,7 @@ func relocsym(s *LSym) { o = r.Xadd if Iself { - if Thearch.Thechar == '6' { + if SysArch.Family == sys.AMD64 { o = 0 } } else if HEADTYPE == obj.Hdarwin { @@ -520,10 +560,13 @@ func relocsym(s *LSym) { o += int64(uint64(Symaddr(rs)) - rs.Sect.Vaddr) } o -= int64(r.Off) // relative to section offset, not symbol + } else if SysArch.Family == sys.ARM { + // see ../arm/asm.go:/machoreloc1 + o += Symaddr(rs) - int64(Ctxt.Cursym.Value) - int64(r.Off) } else { o += int64(r.Siz) } - } else if HEADTYPE == obj.Hwindows && Thearch.Thechar == '6' { // only amd64 needs PCREL + } else if HEADTYPE == obj.Hwindows && SysArch.Family == sys.AMD64 { // only amd64 needs PCREL // PE/COFF's PC32 relocation uses the address after the relocated // bytes as the base. Compensate by skewing the addend. o += int64(r.Siz) @@ -604,14 +647,17 @@ func relocsym(s *LSym) { func reloc() { if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "%5.2f reloc\n", obj.Cputime()) + fmt.Fprintf(Bso, "%5.2f reloc\n", obj.Cputime()) } Bso.Flush() - for s := Ctxt.Textp; s != nil; s = s.Next { + for _, s := range Ctxt.Textp { relocsym(s) } - for s := datap; s != nil; s = s.Next { + for _, sym := range datap { + relocsym(sym) + } + for s := dwarfp; s != nil; s = s.Next { relocsym(s) } } @@ -622,11 +668,9 @@ func dynrelocsym(s *LSym) { if s == rel { return } - var r *Reloc - var targ *LSym for ri := 0; ri < len(s.R); ri++ { - r = &s.R[ri] - targ = r.Sym + r := &s.R[ri] + targ := r.Sym if targ == nil { continue } @@ -639,7 +683,7 @@ func dynrelocsym(s *LSym) { r.Add = int64(targ.Plt) // jmp *addr - if Thearch.Thechar == '8' { + if SysArch.Family == sys.I386 { Adduint8(Ctxt, rel, 0xff) Adduint8(Ctxt, rel, 0x25) Addaddr(Ctxt, rel, targ) @@ -661,9 +705,8 @@ func dynrelocsym(s *LSym) { return } - var r *Reloc for ri := 0; ri < len(s.R); ri++ { - r = &s.R[ri] + r := &s.R[ri] if r.Sym != nil && r.Sym.Type == obj.SDYNIMPORT || r.Type >= 256 { if r.Sym != nil && !r.Sym.Attr.Reachable() { Diag("internal inconsistency: dynamic symbol %s is not reachable.", r.Sym.Name) @@ -673,22 +716,24 @@ func dynrelocsym(s *LSym) { } } -func dynreloc() { +func dynreloc(data *[obj.SXREF][]*LSym) { // -d suppresses dynamic loader format, so we may as well not // compute these sections or mark their symbols as reachable. if Debug['d'] != 0 && HEADTYPE != obj.Hwindows { return } if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "%5.2f reloc\n", obj.Cputime()) + fmt.Fprintf(Bso, "%5.2f reloc\n", obj.Cputime()) } Bso.Flush() - for s := Ctxt.Textp; s != nil; s = s.Next { + for _, s := range Ctxt.Textp { dynrelocsym(s) } - for s := datap; s != nil; s = s.Next { - dynrelocsym(s) + for _, syms := range data { + for _, sym := range syms { + dynrelocsym(sym) + } } if Iself { elfdynhash() @@ -705,7 +750,6 @@ func blk(start *LSym, addr int64, size int64) { } eaddr := addr + size - var p []byte for ; sym != nil; sym = sym.Next { if sym.Type&obj.SSUB != 0 { continue @@ -715,7 +759,7 @@ func blk(start *LSym, addr int64, size int64) { } Ctxt.Cursym = sym if sym.Value < addr { - Diag("phase error: addr=%#x but sym=%#x type=%d", int64(addr), int64(sym.Value), sym.Type) + Diag("phase error: addr=%#x but sym=%#x type=%d", addr, sym.Value, sym.Type) errorexit() } @@ -723,15 +767,14 @@ func blk(start *LSym, addr int64, size int64) { strnput("", int(sym.Value-addr)) addr = sym.Value } - p = sym.P - Cwrite(p) + Cwrite(sym.P) addr += int64(len(sym.P)) if addr < sym.Value+sym.Size { strnput("", int(sym.Value+sym.Size-addr)) addr = sym.Value + sym.Size } if addr != sym.Value+sym.Size { - Diag("phase error: addr=%#x value+size=%#x", int64(addr), int64(sym.Value)+sym.Size) + Diag("phase error: addr=%#x value+size=%#x", addr, sym.Value+sym.Size) errorexit() } @@ -748,29 +791,30 @@ func blk(start *LSym, addr int64, size int64) { func Codeblk(addr int64, size int64) { if Debug['a'] != 0 { - fmt.Fprintf(&Bso, "codeblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos()) + fmt.Fprintf(Bso, "codeblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos()) } - blk(Ctxt.Textp, addr, size) + blkSlice(Ctxt.Textp, addr, size) /* again for printing */ if Debug['a'] == 0 { return } - var sym *LSym - for sym = Ctxt.Textp; sym != nil; sym = sym.Next { + syms := Ctxt.Textp + for i, sym := range syms { if !sym.Attr.Reachable() { continue } if sym.Value >= addr { + syms = syms[i:] break } } eaddr := addr + size var q []byte - for ; sym != nil; sym = sym.Next { + for _, sym := range syms { if !sym.Attr.Reachable() { continue } @@ -779,118 +823,164 @@ func Codeblk(addr int64, size int64) { } if addr < sym.Value { - fmt.Fprintf(&Bso, "%-20s %.8x|", "_", uint64(int64(addr))) + fmt.Fprintf(Bso, "%-20s %.8x|", "_", uint64(addr)) for ; addr < sym.Value; addr++ { - fmt.Fprintf(&Bso, " %.2x", 0) + fmt.Fprintf(Bso, " %.2x", 0) } - fmt.Fprintf(&Bso, "\n") + fmt.Fprintf(Bso, "\n") } - fmt.Fprintf(&Bso, "%.6x\t%-20s\n", uint64(int64(addr)), sym.Name) + fmt.Fprintf(Bso, "%.6x\t%-20s\n", uint64(addr), sym.Name) q = sym.P for len(q) >= 16 { - fmt.Fprintf(&Bso, "%.6x\t% x\n", uint64(addr), q[:16]) + fmt.Fprintf(Bso, "%.6x\t% x\n", uint64(addr), q[:16]) addr += 16 q = q[16:] } if len(q) > 0 { - fmt.Fprintf(&Bso, "%.6x\t% x\n", uint64(addr), q) + fmt.Fprintf(Bso, "%.6x\t% x\n", uint64(addr), q) addr += int64(len(q)) } } if addr < eaddr { - fmt.Fprintf(&Bso, "%-20s %.8x|", "_", uint64(int64(addr))) + fmt.Fprintf(Bso, "%-20s %.8x|", "_", uint64(addr)) for ; addr < eaddr; addr++ { - fmt.Fprintf(&Bso, " %.2x", 0) + fmt.Fprintf(Bso, " %.2x", 0) } } Bso.Flush() } +// blkSlice is a variant of blk that processes slices. +// After text symbols are converted from a linked list to a slice, +// delete blk and give this function its name. +func blkSlice(syms []*LSym, addr, size int64) { + for i, s := range syms { + if s.Type&obj.SSUB == 0 && s.Value >= addr { + syms = syms[i:] + break + } + } + + eaddr := addr + size + for _, s := range syms { + if s.Type&obj.SSUB != 0 { + continue + } + if s.Value >= eaddr { + break + } + Ctxt.Cursym = s + if s.Value < addr { + Diag("phase error: addr=%#x but sym=%#x type=%d", addr, s.Value, s.Type) + errorexit() + } + if addr < s.Value { + strnput("", int(s.Value-addr)) + addr = s.Value + } + Cwrite(s.P) + addr += int64(len(s.P)) + if addr < s.Value+s.Size { + strnput("", int(s.Value+s.Size-addr)) + addr = s.Value + s.Size + } + if addr != s.Value+s.Size { + Diag("phase error: addr=%#x value+size=%#x", addr, s.Value+s.Size) + errorexit() + } + if s.Value+s.Size >= eaddr { + break + } + } + + if addr < eaddr { + strnput("", int(eaddr-addr)) + } + Cflush() +} + func Datblk(addr int64, size int64) { if Debug['a'] != 0 { - fmt.Fprintf(&Bso, "datblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos()) + fmt.Fprintf(Bso, "datblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos()) } - blk(datap, addr, size) + blkSlice(datap, addr, size) /* again for printing */ if Debug['a'] == 0 { return } - var sym *LSym - for sym = datap; sym != nil; sym = sym.Next { + syms := datap + for i, sym := range syms { if sym.Value >= addr { + syms = syms[i:] break } } eaddr := addr + size - var ep []byte - var i int64 - var p []byte - var r *Reloc - var rsname string - var typ string - for ; sym != nil; sym = sym.Next { + for _, sym := range syms { if sym.Value >= eaddr { break } if addr < sym.Value { - fmt.Fprintf(&Bso, "\t%.8x| 00 ...\n", uint64(addr)) + fmt.Fprintf(Bso, "\t%.8x| 00 ...\n", uint64(addr)) addr = sym.Value } - fmt.Fprintf(&Bso, "%s\n\t%.8x|", sym.Name, uint(addr)) - p = sym.P - ep = p[len(sym.P):] - for -cap(p) < -cap(ep) { - if -cap(p) > -cap(sym.P) && int(-cap(p)+cap(sym.P))%16 == 0 { - fmt.Fprintf(&Bso, "\n\t%.8x|", uint(addr+int64(-cap(p)+cap(sym.P)))) + fmt.Fprintf(Bso, "%s\n\t%.8x|", sym.Name, uint64(addr)) + for i, b := range sym.P { + if i > 0 && i%16 == 0 { + fmt.Fprintf(Bso, "\n\t%.8x|", uint64(addr)+uint64(i)) } - fmt.Fprintf(&Bso, " %.2x", p[0]) - p = p[1:] + fmt.Fprintf(Bso, " %.2x", b) } addr += int64(len(sym.P)) for ; addr < sym.Value+sym.Size; addr++ { - fmt.Fprintf(&Bso, " %.2x", 0) + fmt.Fprintf(Bso, " %.2x", 0) } - fmt.Fprintf(&Bso, "\n") - - if Linkmode == LinkExternal { - for i = 0; i < int64(len(sym.R)); i++ { - r = &sym.R[i] - rsname = "" - if r.Sym != nil { - rsname = r.Sym.Name - } - typ = "?" - switch r.Type { - case obj.R_ADDR: - typ = "addr" - - case obj.R_PCREL: - typ = "pcrel" + fmt.Fprintf(Bso, "\n") - case obj.R_CALL: - typ = "call" - } - - fmt.Fprintf(&Bso, "\treloc %.8x/%d %s %s+%#x [%#x]\n", uint(sym.Value+int64(r.Off)), r.Siz, typ, rsname, int64(r.Add), int64(r.Sym.Value+r.Add)) + if Linkmode != LinkExternal { + continue + } + for _, r := range sym.R { + rsname := "" + if r.Sym != nil { + rsname = r.Sym.Name + } + typ := "?" + switch r.Type { + case obj.R_ADDR: + typ = "addr" + case obj.R_PCREL: + typ = "pcrel" + case obj.R_CALL: + typ = "call" } + fmt.Fprintf(Bso, "\treloc %.8x/%d %s %s+%#x [%#x]\n", uint(sym.Value+int64(r.Off)), r.Siz, typ, rsname, r.Add, r.Sym.Value+r.Add) } } if addr < eaddr { - fmt.Fprintf(&Bso, "\t%.8x| 00 ...\n", uint(addr)) + fmt.Fprintf(Bso, "\t%.8x| 00 ...\n", uint(addr)) } - fmt.Fprintf(&Bso, "\t%.8x|\n", uint(eaddr)) + fmt.Fprintf(Bso, "\t%.8x|\n", uint(eaddr)) +} + +func Dwarfblk(addr int64, size int64) { + if Debug['a'] != 0 { + fmt.Fprintf(Bso, "dwarfblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos()) + } + + blk(dwarfp, addr, size) } var zeros [512]byte @@ -938,7 +1028,7 @@ func addstrdata(name string, value string) { s.Attr |= AttrDuplicateOK reachable := s.Attr.Reachable() Addaddr(Ctxt, s, sp) - adduintxx(Ctxt, s, uint64(len(value)), Thearch.Ptrsize) + adduintxx(Ctxt, s, uint64(len(value)), SysArch.PtrSize) // addstring, addaddr, etc., mark the symbols as reachable. // In this case that is not necessarily true, so stick to what @@ -965,16 +1055,14 @@ func Addstring(s *LSym, str string) int64 { s.Type = obj.SNOPTRDATA } s.Attr |= AttrReachable - r := int32(s.Size) - n := len(str) + 1 + r := s.Size if s.Name == ".shstrtab" { elfsetstring(str, int(r)) } - Symgrow(Ctxt, s, int64(r)+int64(n)) - copy(s.P[r:], str) - s.P[int(r)+len(str)] = 0 - s.Size += int64(n) - return int64(r) + s.P = append(s.P, str...) + s.P = append(s.P, 0) + s.Size = int64(len(s.P)) + return r } // addgostring adds str, as a Go string value, to s. symname is the name of the @@ -1031,7 +1119,7 @@ func symalign(s *LSym) int32 { } else if s.Align != 0 { return min } - if strings.HasPrefix(s.Name, "go.string.") && !strings.HasPrefix(s.Name, "go.string.hdr.") { + if (strings.HasPrefix(s.Name, "go.string.") && !strings.HasPrefix(s.Name, "go.string.hdr.")) || strings.HasPrefix(s.Name, "type..namedata.") { // String data is just bytes. // If we align it, we waste a lot of space to padding. return min @@ -1047,22 +1135,6 @@ func aligndatsize(datsize int64, s *LSym) int64 { return Rnd(datsize, int64(symalign(s))) } -// maxalign returns the maximum required alignment for -// the list of symbols s; the list stops when s->type exceeds type. -func maxalign(s *LSym, type_ int) int32 { - var align int32 - - max := int32(0) - for ; s != nil && int(s.Type) <= type_; s = s.Next { - align = symalign(s) - if max < align { - max = align - } - } - - return max -} - const debugGCProg = false type GCProg struct { @@ -1084,7 +1156,7 @@ func (p *GCProg) writeByte(x byte) { } func (p *GCProg) End(size int64) { - p.w.ZeroUntil(size / int64(Thearch.Ptrsize)) + p.w.ZeroUntil(size / int64(SysArch.PtrSize)) p.w.End() if debugGCProg { fmt.Fprintf(os.Stderr, "ld: end GCProg\n") @@ -1100,7 +1172,7 @@ func (p *GCProg) AddSym(s *LSym) { return } - ptrsize := int64(Thearch.Ptrsize) + ptrsize := int64(SysArch.PtrSize) nptr := decodetype_ptrdata(typ) / ptrsize if debugGCProg { @@ -1124,236 +1196,170 @@ func (p *GCProg) AddSym(s *LSym) { p.w.Append(prog[4:], nptr) } +// dataSortKey is used to sort a slice of data symbol *LSym pointers. +// The sort keys are kept inline to improve cache behaviour while sorting. type dataSortKey struct { - // keep sort keys inline to improve cache behaviour while sorting - Type int16 - Size int64 - Name string - - Lsym *LSym + size int64 + name string + lsym *LSym } -type dataSlice []dataSortKey - -func (d dataSlice) Len() int { return len(d) } -func (d dataSlice) Swap(i, j int) { d[i], d[j] = d[j], d[i] } -func (d dataSlice) Less(i, j int) bool { - s1, s2 := &d[i], &d[j] - if s1.Type != s2.Type { - return s1.Type < s2.Type - } +type bySizeAndName []dataSortKey - // For ppc64, we want to interleave the .got and .toc sections - // from input files. Both are type SELFGOT, so in that case - // fall through to the name comparison (conveniently, .got - // sorts before .toc). - if s1.Type != obj.SELFGOT && s1.Size != s2.Size { - return s1.Size < s2.Size +func (d bySizeAndName) Len() int { return len(d) } +func (d bySizeAndName) Swap(i, j int) { d[i], d[j] = d[j], d[i] } +func (d bySizeAndName) Less(i, j int) bool { + s1, s2 := d[i], d[j] + if s1.size != s2.size { + return s1.size < s2.size } - - return s1.Name < s2.Name + return s1.name < s2.name } -func growdatsize(datsizep *int64, s *LSym) { - datsize := *datsizep - const cutoff int64 = 2e9 // 2 GB (or so; looks better in errors than 2^31) - switch { - case s.Size < 0: - Diag("%s: negative size (%d bytes)", s.Name, s.Size) - case s.Size > cutoff: - Diag("%s: symbol too large (%d bytes)", s.Name, s.Size) - case datsize <= cutoff && datsize+s.Size > cutoff: - Diag("%s: too much data (over %d bytes)", s.Name, cutoff) - } - *datsizep = datsize + s.Size -} +const cutoff int64 = 2e9 // 2 GB (or so; looks better in errors than 2^31) -func list2Slice(head *LSym) dataSlice { - n := 0 - for s := datap; s != nil; s = s.Next { - n++ +func checkdatsize(datsize int64, symn int) { + if datsize > cutoff { + Diag("too much data in section %v (over %d bytes)", symn, cutoff) } - slice := make(dataSlice, n) - i := 0 - for s := datap; s != nil; s = s.Next { - k := &slice[i] - k.Type = s.Type - k.Size = s.Size - k.Name = s.Name - k.Lsym = s - - i++ - } - return slice } -func slice2List(d dataSlice) *LSym { - for i := 0; i < len(d)-1; i++ { - d[i].Lsym.Next = d[i+1].Lsym +func list2slice(s *LSym) []*LSym { + var syms []*LSym + for ; s != nil; s = s.Next { + syms = append(syms, s) } - d[len(d)-1].Lsym.Next = nil - return d[0].Lsym + return syms } -func dataSort(head *LSym) *LSym { - d := list2Slice(head) - sort.Sort(d) - return slice2List(d) -} +// datap is a collection of reachable data symbols in address order. +// Generated by dodata. +var datap []*LSym func dodata() { if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "%5.2f dodata\n", obj.Cputime()) + fmt.Fprintf(Bso, "%5.2f dodata\n", obj.Cputime()) } Bso.Flush() - var last *LSym - datap = nil - + // Collect data symbols by type into data. + var data [obj.SXREF][]*LSym for _, s := range Ctxt.Allsym { if !s.Attr.Reachable() || s.Attr.Special() { continue } - if obj.STEXT < s.Type && s.Type < obj.SXREF { - if s.Attr.OnList() { - log.Fatalf("symbol %s listed multiple times", s.Name) - } - s.Attr |= AttrOnList - if last == nil { - datap = s - } else { - last.Next = s - } - s.Next = nil - last = s - } - } - - for s := datap; s != nil; s = s.Next { - if int64(len(s.P)) > s.Size { - Diag("%s: initialize bounds (%d < %d)", s.Name, int64(s.Size), len(s.P)) + if s.Type <= obj.STEXT || s.Type >= obj.SXREF { + continue } + data[s.Type] = append(data[s.Type], s) } - /* - * now that we have the datap list, but before we start - * to assign addresses, record all the necessary - * dynamic relocations. these will grow the relocation - * symbol, which is itself data. - * - * on darwin, we need the symbol table numbers for dynreloc. - */ + // Now that we have the data symbols, but before we start + // to assign addresses, record all the necessary + // dynamic relocations. These will grow the relocation + // symbol, which is itself data. + // + // On darwin, we need the symbol table numbers for dynreloc. if HEADTYPE == obj.Hdarwin { machosymorder() } - dynreloc() - - /* some symbols may no longer belong in datap (Mach-O) */ - var l **LSym - var s *LSym - for l = &datap; ; { - s = *l - if s == nil { - break - } - - if s.Type <= obj.STEXT || obj.SXREF <= s.Type { - *l = s.Next - } else { - l = &s.Next - } - } - - *l = nil + dynreloc(&data) if UseRelro() { // "read only" data with relocations needs to go in its own section // when building a shared library. We do this by boosting objects of // type SXXX with relocations to type SXXXRELRO. - for s := datap; s != nil; s = s.Next { - if (s.Type >= obj.STYPE && s.Type <= obj.SFUNCTAB && len(s.R) > 0) || s.Type == obj.STYPE || s.Type == obj.SGOSTRINGHDR { - s.Type += (obj.STYPERELRO - obj.STYPE) - if s.Outer != nil { - s.Outer.Type = s.Type - } - } - } - // Check that we haven't made two symbols with the same .Outer into - // different types (because references two symbols with non-nil Outer - // become references to the outer symbol + offset it's vital that the - // symbol and the outer end up in the same section). - for s := datap; s != nil; s = s.Next { - if s.Outer != nil && s.Outer.Type != s.Type { - Diag("inconsistent types for %s and its Outer %s (%d != %d)", - s.Name, s.Outer.Name, s.Type, s.Outer.Type) - } - } - - } + for symnro := int16(obj.STYPE); symnro < obj.STYPERELRO; symnro++ { + symnrelro := symnro + obj.STYPERELRO - obj.STYPE - datap = dataSort(datap) + ro := []*LSym{} + relro := data[symnrelro] - if Iself { - // Make .rela and .rela.plt contiguous, the ELF ABI requires this - // and Solaris actually cares. - var relplt *LSym - for l = &datap; *l != nil; l = &(*l).Next { - if (*l).Name == ".rel.plt" || (*l).Name == ".rela.plt" { - relplt = (*l) - *l = (*l).Next - break + for _, s := range data[symnro] { + isRelro := len(s.R) > 0 + switch s.Type { + case obj.STYPE, obj.SGOSTRINGHDR, obj.STYPERELRO, obj.SGOSTRINGHDRRELRO: + // Symbols are not sorted yet, so it is possible + // that an Outer symbol has been changed to a + // relro Type before it reaches here. + isRelro = true + } + if isRelro { + s.Type = symnrelro + if s.Outer != nil { + s.Outer.Type = s.Type + } + relro = append(relro, s) + } else { + ro = append(ro, s) + } } - } - if relplt != nil { - for s = datap; s != nil; s = s.Next { - if s.Name == ".rel" || s.Name == ".rela" { - relplt.Next = s.Next - s.Next = relplt + + // Check that we haven't made two symbols with the same .Outer into + // different types (because references two symbols with non-nil Outer + // become references to the outer symbol + offset it's vital that the + // symbol and the outer end up in the same section). + for _, s := range relro { + if s.Outer != nil && s.Outer.Type != s.Type { + Diag("inconsistent types for %s and its Outer %s (%d != %d)", + s.Name, s.Outer.Name, s.Type, s.Outer.Type) } } + + data[symnro] = ro + data[symnrelro] = relro } } - /* - * allocate sections. list is sorted by type, - * so we can just walk it for each piece we want to emit. - * segdata is processed before segtext, because we need - * to see all symbols in the .data and .bss sections in order - * to generate garbage collection information. - */ - - /* begin segdata */ - - /* skip symbols belonging to segtext */ - s = datap - - for ; s != nil && s.Type < obj.SELFSECT; s = s.Next { + // Sort symbols. + var dataMaxAlign [obj.SXREF]int32 + var wg sync.WaitGroup + for symn := range data { + symn := symn + wg.Add(1) + go func() { + data[symn], dataMaxAlign[symn] = dodataSect(symn, data[symn]) + wg.Done() + }() } + wg.Wait() - /* writable ELF sections */ + // Allocate sections. + // Data is processed before segtext, because we need + // to see all symbols in the .data and .bss sections in order + // to generate garbage collection information. datsize := int64(0) - var sect *Section - for ; s != nil && s.Type < obj.SELFGOT; s = s.Next { - sect = addsection(&Segdata, s.Name, 06) - sect.Align = symalign(s) - datsize = Rnd(datsize, int64(sect.Align)) - sect.Vaddr = uint64(datsize) - s.Sect = sect - s.Type = obj.SDATA - s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) - sect.Length = uint64(datsize) - sect.Vaddr + // Writable sections. + writableSects := []int{ + obj.SELFSECT, + obj.SMACHO, + obj.SMACHOGOT, + obj.SWINDOWS, + } + for _, symn := range writableSects { + for _, s := range data[symn] { + sect := addsection(&Segdata, s.Name, 06) + sect.Align = symalign(s) + datsize = Rnd(datsize, int64(sect.Align)) + sect.Vaddr = uint64(datsize) + s.Sect = sect + s.Type = obj.SDATA + s.Value = int64(uint64(datsize) - sect.Vaddr) + datsize += s.Size + sect.Length = uint64(datsize) - sect.Vaddr + } + checkdatsize(datsize, symn) } - /* .got (and .toc on ppc64) */ - if s.Type == obj.SELFGOT { + // .got (and .toc on ppc64) + if len(data[obj.SELFGOT]) > 0 { sect := addsection(&Segdata, ".got", 06) - sect.Align = maxalign(s, obj.SELFGOT) + sect.Align = dataMaxAlign[obj.SELFGOT] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) var toc *LSym - for ; s != nil && s.Type == obj.SELFGOT; s = s.Next { + for _, s := range data[obj.SELFGOT] { datsize = aligndatsize(datsize, s) s.Sect = sect s.Type = obj.SDATA @@ -1361,7 +1367,6 @@ func dodata() { // Resolve .TOC. symbol for this object file (ppc64) toc = Linkrlookup(Ctxt, ".TOC.", int(s.Version)) - if toc != nil { toc.Sect = sect toc.Outer = s @@ -1371,28 +1376,27 @@ func dodata() { toc.Value = 0x8000 } - growdatsize(&datsize, s) + datsize += s.Size } - + checkdatsize(datsize, obj.SELFGOT) sect.Length = uint64(datsize) - sect.Vaddr } /* pointer-free data */ - sect = addsection(&Segdata, ".noptrdata", 06) - - sect.Align = maxalign(s, obj.SINITARR-1) + sect := addsection(&Segdata, ".noptrdata", 06) + sect.Align = dataMaxAlign[obj.SNOPTRDATA] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.noptrdata", 0).Sect = sect Linklookup(Ctxt, "runtime.enoptrdata", 0).Sect = sect - for ; s != nil && s.Type < obj.SINITARR; s = s.Next { + for _, s := range data[obj.SNOPTRDATA] { datsize = aligndatsize(datsize, s) s.Sect = sect s.Type = obj.SDATA s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) + datsize += s.Size } - + checkdatsize(datsize, obj.SNOPTRDATA) sect.Length = uint64(datsize) - sect.Vaddr hasinitarr := Linkshared @@ -1402,116 +1406,102 @@ func dodata() { case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared: hasinitarr = true } - if hasinitarr { sect := addsection(&Segdata, ".init_array", 06) - sect.Align = maxalign(s, obj.SINITARR) + sect.Align = dataMaxAlign[obj.SINITARR] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) - for ; s != nil && s.Type == obj.SINITARR; s = s.Next { + for _, s := range data[obj.SINITARR] { datsize = aligndatsize(datsize, s) s.Sect = sect s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) + datsize += s.Size } - sect.Length = uint64(datsize) - sect.Vaddr + checkdatsize(datsize, obj.SINITARR) } /* data */ sect = addsection(&Segdata, ".data", 06) - sect.Align = maxalign(s, obj.SBSS-1) + sect.Align = dataMaxAlign[obj.SDATA] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.data", 0).Sect = sect Linklookup(Ctxt, "runtime.edata", 0).Sect = sect var gc GCProg gc.Init("runtime.gcdata") - for ; s != nil && s.Type < obj.SBSS; s = s.Next { - if s.Type == obj.SINITARR { - Ctxt.Cursym = s - Diag("unexpected symbol type %d", s.Type) - } - + for _, s := range data[obj.SDATA] { s.Sect = sect s.Type = obj.SDATA datsize = aligndatsize(datsize, s) s.Value = int64(uint64(datsize) - sect.Vaddr) gc.AddSym(s) - growdatsize(&datsize, s) + datsize += s.Size } + checkdatsize(datsize, obj.SDATA) sect.Length = uint64(datsize) - sect.Vaddr gc.End(int64(sect.Length)) /* bss */ sect = addsection(&Segdata, ".bss", 06) - sect.Align = maxalign(s, obj.SNOPTRBSS-1) + sect.Align = dataMaxAlign[obj.SBSS] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.bss", 0).Sect = sect Linklookup(Ctxt, "runtime.ebss", 0).Sect = sect gc = GCProg{} gc.Init("runtime.gcbss") - for ; s != nil && s.Type < obj.SNOPTRBSS; s = s.Next { + for _, s := range data[obj.SBSS] { s.Sect = sect datsize = aligndatsize(datsize, s) s.Value = int64(uint64(datsize) - sect.Vaddr) gc.AddSym(s) - growdatsize(&datsize, s) + datsize += s.Size } + checkdatsize(datsize, obj.SBSS) sect.Length = uint64(datsize) - sect.Vaddr gc.End(int64(sect.Length)) /* pointer-free bss */ sect = addsection(&Segdata, ".noptrbss", 06) - - sect.Align = maxalign(s, obj.SNOPTRBSS) + sect.Align = dataMaxAlign[obj.SNOPTRBSS] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.noptrbss", 0).Sect = sect Linklookup(Ctxt, "runtime.enoptrbss", 0).Sect = sect - for ; s != nil && s.Type == obj.SNOPTRBSS; s = s.Next { + for _, s := range data[obj.SNOPTRBSS] { datsize = aligndatsize(datsize, s) s.Sect = sect s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) + datsize += s.Size } sect.Length = uint64(datsize) - sect.Vaddr Linklookup(Ctxt, "runtime.end", 0).Sect = sect + checkdatsize(datsize, obj.SNOPTRBSS) - // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. - if datsize != int64(uint32(datsize)) { - Diag("data or bss segment too large") - } - - if s != nil && s.Type == obj.STLSBSS { + if len(data[obj.STLSBSS]) > 0 { + var sect *Section if Iself && (Linkmode == LinkExternal || Debug['d'] == 0) && HEADTYPE != obj.Hopenbsd { sect = addsection(&Segdata, ".tbss", 06) - sect.Align = int32(Thearch.Ptrsize) + sect.Align = int32(SysArch.PtrSize) sect.Vaddr = 0 - } else { - sect = nil } datsize = 0 - for ; s != nil && s.Type == obj.STLSBSS; s = s.Next { + for _, s := range data[obj.STLSBSS] { datsize = aligndatsize(datsize, s) s.Sect = sect s.Value = datsize - growdatsize(&datsize, s) + datsize += s.Size } + checkdatsize(datsize, obj.STLSBSS) if sect != nil { sect.Length = uint64(datsize) } } - if s != nil { - Ctxt.Cursym = nil - Diag("unexpected symbol type %d for %s", s.Type, s.Name) - } - /* * We finished data, begin read-only data. * Not all systems support a separate read-only non-executable data section. @@ -1529,39 +1519,62 @@ func dodata() { segro = &Segtext } - s = datap - datsize = 0 /* read-only executable ELF, Mach-O sections */ - for ; s != nil && s.Type < obj.STYPE; s = s.Next { - sect = addsection(&Segtext, s.Name, 04) + if len(data[obj.STEXT]) != 0 { + Diag("dodata found an STEXT symbol: %s", data[obj.STEXT][0].Name) + } + for _, s := range data[obj.SELFRXSECT] { + sect := addsection(&Segtext, s.Name, 04) sect.Align = symalign(s) datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) s.Sect = sect s.Type = obj.SRODATA s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) + datsize += s.Size sect.Length = uint64(datsize) - sect.Vaddr + checkdatsize(datsize, obj.SELFRXSECT) } /* read-only data */ sect = addsection(segro, ".rodata", 04) - sect.Align = maxalign(s, obj.STYPERELRO-1) - datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = 0 Linklookup(Ctxt, "runtime.rodata", 0).Sect = sect Linklookup(Ctxt, "runtime.erodata", 0).Sect = sect - for ; s != nil && s.Type < obj.STYPERELRO; s = s.Next { - datsize = aligndatsize(datsize, s) - s.Sect = sect - s.Type = obj.SRODATA - s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) + if !UseRelro() { + Linklookup(Ctxt, "runtime.types", 0).Sect = sect + Linklookup(Ctxt, "runtime.etypes", 0).Sect = sect + } + roSects := []int{ + obj.STYPE, + obj.SSTRING, + obj.SGOSTRING, + obj.SGOSTRINGHDR, + obj.SGOFUNC, + obj.SGCBITS, + obj.SRODATA, + obj.SFUNCTAB, + } + for _, symn := range roSects { + align := dataMaxAlign[symn] + if sect.Align < align { + sect.Align = align + } + } + datsize = Rnd(datsize, int64(sect.Align)) + for _, symn := range roSects { + for _, s := range data[symn] { + datsize = aligndatsize(datsize, s) + s.Sect = sect + s.Type = obj.SRODATA + s.Value = int64(uint64(datsize) - sect.Vaddr) + datsize += s.Size + } + checkdatsize(datsize, symn) } - sect.Length = uint64(datsize) - sect.Vaddr // There is some data that are conceptually read-only but are written to by @@ -1583,18 +1596,38 @@ func dodata() { /* data only written by relocations */ sect = addsection(segro, ".data.rel.ro", 06) - sect.Align = maxalign(s, obj.STYPELINK-1) - datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = 0 - for ; s != nil && s.Type < obj.STYPELINK; s = s.Next { - datsize = aligndatsize(datsize, s) - if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect { - Diag("s.Outer (%s) in different section from s (%s)", s.Outer.Name, s.Name) + Linklookup(Ctxt, "runtime.types", 0).Sect = sect + Linklookup(Ctxt, "runtime.etypes", 0).Sect = sect + relroSects := []int{ + obj.STYPERELRO, + obj.SSTRINGRELRO, + obj.SGOSTRINGRELRO, + obj.SGOSTRINGHDRRELRO, + obj.SGOFUNCRELRO, + obj.SGCBITSRELRO, + obj.SRODATARELRO, + obj.SFUNCTABRELRO, + } + for _, symn := range relroSects { + align := dataMaxAlign[symn] + if sect.Align < align { + sect.Align = align } - s.Sect = sect - s.Type = obj.SRODATA - s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) + } + datsize = Rnd(datsize, int64(sect.Align)) + for _, symn := range relroSects { + for _, s := range data[symn] { + datsize = aligndatsize(datsize, s) + if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect { + Diag("s.Outer (%s) in different section from s (%s)", s.Outer.Name, s.Name) + } + s.Sect = sect + s.Type = obj.SRODATA + s.Value = int64(uint64(datsize) - sect.Vaddr) + datsize += s.Size + } + checkdatsize(datsize, symn) } sect.Length = uint64(datsize) - sect.Vaddr @@ -1603,78 +1636,74 @@ func dodata() { /* typelink */ sect = addsection(segro, relro_prefix+".typelink", relro_perms) - - sect.Align = maxalign(s, obj.STYPELINK) + sect.Align = dataMaxAlign[obj.STYPELINK] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.typelink", 0).Sect = sect Linklookup(Ctxt, "runtime.etypelink", 0).Sect = sect - for ; s != nil && s.Type == obj.STYPELINK; s = s.Next { + for _, s := range data[obj.STYPELINK] { datsize = aligndatsize(datsize, s) s.Sect = sect s.Type = obj.SRODATA s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) + datsize += s.Size } - + checkdatsize(datsize, obj.STYPELINK) sect.Length = uint64(datsize) - sect.Vaddr /* itablink */ sect = addsection(segro, relro_prefix+".itablink", relro_perms) - - sect.Align = maxalign(s, obj.SITABLINK) + sect.Align = dataMaxAlign[obj.SITABLINK] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.itablink", 0).Sect = sect Linklookup(Ctxt, "runtime.eitablink", 0).Sect = sect - for ; s != nil && s.Type == obj.SITABLINK; s = s.Next { + for _, s := range data[obj.SITABLINK] { datsize = aligndatsize(datsize, s) s.Sect = sect s.Type = obj.SRODATA s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) + datsize += s.Size } - + checkdatsize(datsize, obj.SITABLINK) sect.Length = uint64(datsize) - sect.Vaddr /* gosymtab */ sect = addsection(segro, relro_prefix+".gosymtab", relro_perms) - - sect.Align = maxalign(s, obj.SPCLNTAB-1) + sect.Align = dataMaxAlign[obj.SSYMTAB] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.symtab", 0).Sect = sect Linklookup(Ctxt, "runtime.esymtab", 0).Sect = sect - for ; s != nil && s.Type < obj.SPCLNTAB; s = s.Next { + for _, s := range data[obj.SSYMTAB] { datsize = aligndatsize(datsize, s) s.Sect = sect s.Type = obj.SRODATA s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) + datsize += s.Size } - + checkdatsize(datsize, obj.SSYMTAB) sect.Length = uint64(datsize) - sect.Vaddr /* gopclntab */ sect = addsection(segro, relro_prefix+".gopclntab", relro_perms) - - sect.Align = maxalign(s, obj.SELFROSECT-1) + sect.Align = dataMaxAlign[obj.SPCLNTAB] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.pclntab", 0).Sect = sect Linklookup(Ctxt, "runtime.epclntab", 0).Sect = sect - for ; s != nil && s.Type < obj.SELFROSECT; s = s.Next { + for _, s := range data[obj.SPCLNTAB] { datsize = aligndatsize(datsize, s) s.Sect = sect s.Type = obj.SRODATA s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) + datsize += s.Size } - + checkdatsize(datsize, obj.SRODATA) sect.Length = uint64(datsize) - sect.Vaddr /* read-only ELF, Mach-O sections */ - for ; s != nil && s.Type < obj.SELFSECT; s = s.Next { + for _, s := range data[obj.SELFROSECT] { sect = addsection(segro, s.Name, 04) sect.Align = symalign(s) datsize = Rnd(datsize, int64(sect.Align)) @@ -1682,15 +1711,65 @@ func dodata() { s.Sect = sect s.Type = obj.SRODATA s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) + datsize += s.Size sect.Length = uint64(datsize) - sect.Vaddr } + checkdatsize(datsize, obj.SELFROSECT) + + for _, s := range data[obj.SMACHOPLT] { + sect = addsection(segro, s.Name, 04) + sect.Align = symalign(s) + datsize = Rnd(datsize, int64(sect.Align)) + sect.Vaddr = uint64(datsize) + s.Sect = sect + s.Type = obj.SRODATA + s.Value = int64(uint64(datsize) - sect.Vaddr) + datsize += s.Size + sect.Length = uint64(datsize) - sect.Vaddr + } + checkdatsize(datsize, obj.SMACHOPLT) // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. if datsize != int64(uint32(datsize)) { Diag("read-only data segment too large") } + for symn := obj.SELFRXSECT; symn < obj.SXREF; symn++ { + datap = append(datap, data[symn]...) + } + + dwarfgeneratedebugsyms() + + var s *LSym + for s = dwarfp; s != nil && s.Type == obj.SDWARFSECT; s = s.Next { + sect = addsection(&Segdwarf, s.Name, 04) + sect.Align = 1 + datsize = Rnd(datsize, int64(sect.Align)) + sect.Vaddr = uint64(datsize) + s.Sect = sect + s.Type = obj.SRODATA + s.Value = int64(uint64(datsize) - sect.Vaddr) + datsize += s.Size + sect.Length = uint64(datsize) - sect.Vaddr + } + checkdatsize(datsize, obj.SDWARFSECT) + + if s != nil { + sect = addsection(&Segdwarf, ".debug_info", 04) + sect.Align = 1 + datsize = Rnd(datsize, int64(sect.Align)) + sect.Vaddr = uint64(datsize) + for ; s != nil && s.Type == obj.SDWARFINFO; s = s.Next { + s.Sect = sect + s.Type = obj.SRODATA + s.Value = int64(uint64(datsize) - sect.Vaddr) + s.Attr |= AttrLocal + datsize += s.Size + } + sect.Length = uint64(datsize) - sect.Vaddr + checkdatsize(datsize, obj.SDWARFINFO) + } + /* number the sections */ n := int32(1) @@ -1706,6 +1785,97 @@ func dodata() { sect.Extnum = int16(n) n++ } + for sect := Segdwarf.Sect; sect != nil; sect = sect.Next { + sect.Extnum = int16(n) + n++ + } +} + +func dodataSect(symn int, syms []*LSym) (result []*LSym, maxAlign int32) { + if HEADTYPE == obj.Hdarwin { + // Some symbols may no longer belong in syms + // due to movement in machosymorder. + newSyms := make([]*LSym, 0, len(syms)) + for _, s := range syms { + if int(s.Type) == symn { + newSyms = append(newSyms, s) + } + } + syms = newSyms + } + + symsSort := make([]dataSortKey, len(syms)) + for i, s := range syms { + if s.Attr.OnList() { + log.Fatalf("symbol %s listed multiple times", s.Name) + } + s.Attr |= AttrOnList + switch { + case s.Size < int64(len(s.P)): + Diag("%s: initialize bounds (%d < %d)", s.Name, s.Size, len(s.P)) + case s.Size < 0: + Diag("%s: negative size (%d bytes)", s.Name, s.Size) + case s.Size > cutoff: + Diag("%s: symbol too large (%d bytes)", s.Name, s.Size) + } + + symsSort[i] = dataSortKey{ + size: s.Size, + name: s.Name, + lsym: s, + } + + switch s.Type { + case obj.SELFGOT: + // For ppc64, we want to interleave the .got and .toc sections + // from input files. Both are type SELFGOT, so in that case + // we skip size comparison and fall through to the name + // comparison (conveniently, .got sorts before .toc). + symsSort[i].size = 0 + case obj.STYPELINK: + // Sort typelinks by the rtype.string field so the reflect + // package can binary search type links. + symsSort[i].name = string(decodetype_str(s.R[0].Sym)) + } + } + + sort.Sort(bySizeAndName(symsSort)) + + for i, symSort := range symsSort { + syms[i] = symSort.lsym + align := symalign(symSort.lsym) + if maxAlign < align { + maxAlign = align + } + } + + if Iself && symn == obj.SELFROSECT { + // Make .rela and .rela.plt contiguous, the ELF ABI requires this + // and Solaris actually cares. + reli, plti := -1, -1 + for i, s := range syms { + switch s.Name { + case ".rel.plt", ".rela.plt": + plti = i + case ".rel", ".rela": + reli = i + } + } + if reli >= 0 && plti >= 0 && plti != reli+1 { + var first, second int + if plti > reli { + first, second = reli, plti + } else { + first, second = plti, reli + } + rel, plt := syms[reli], syms[plti] + copy(syms[first+2:], syms[first+1:second]) + syms[first+0] = rel + syms[first+1] = plt + } + } + + return syms, maxAlign } // Add buildid to beginning of text segment, on non-ELF systems. @@ -1727,14 +1897,13 @@ func textbuildid() { sym.P = []byte(data) sym.Size = int64(len(sym.P)) - sym.Next = Ctxt.Textp - Ctxt.Textp = sym + Ctxt.Textp = append(Ctxt.Textp, nil) + copy(Ctxt.Textp[1:], Ctxt.Textp) + Ctxt.Textp[0] = sym } // assign addresses to text func textaddress() { - var sub *LSym - addsection(&Segtext, ".text", 05) // Assign PCs in text segment. @@ -1750,7 +1919,7 @@ func textaddress() { } va := uint64(INITTEXT) sect.Vaddr = va - for sym := Ctxt.Textp; sym != nil; sym = sym.Next { + for _, sym := range Ctxt.Textp { sym.Sect = sect if sym.Type&obj.SSUB != 0 { continue @@ -1761,7 +1930,7 @@ func textaddress() { va = uint64(Rnd(int64(va), int64(Funcalign))) } sym.Value = 0 - for sub = sym; sub != nil; sub = sub.Sub { + for sub := sym; sub != nil; sub = sub.Sub { sub.Value += int64(va) } if sym.Size == 0 && sym.Sub != nil { @@ -1857,6 +2026,29 @@ func address() { Segdata.Filelen = bss.Vaddr - Segdata.Vaddr + va = uint64(Rnd(int64(va), int64(INITRND))) + Segdwarf.Rwx = 06 + Segdwarf.Vaddr = va + Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(INITRND))) + Segdwarf.Filelen = 0 + if HEADTYPE == obj.Hwindows { + Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(PEFILEALIGN))) + } + for s := Segdwarf.Sect; s != nil; s = s.Next { + vlen = int64(s.Length) + if s.Next != nil { + vlen = int64(s.Next.Vaddr - s.Vaddr) + } + s.Vaddr = va + va += uint64(vlen) + if HEADTYPE == obj.Hwindows { + va = uint64(Rnd(int64(va), PEFILEALIGN)) + } + Segdwarf.Length = va - Segdwarf.Vaddr + } + + Segdwarf.Filelen = va - Segdwarf.Vaddr + text := Segtext.Sect var rodata *Section if Segrodata.Sect != nil { @@ -1864,23 +2056,34 @@ func address() { } else { rodata = text.Next } + var relrodata *Section typelink := rodata.Next if UseRelro() { // There is another section (.data.rel.ro) when building a shared // object on elf systems. + relrodata = typelink typelink = typelink.Next } itablink := typelink.Next symtab := itablink.Next pclntab := symtab.Next - var sub *LSym - for sym := datap; sym != nil; sym = sym.Next { + for _, s := range datap { + Ctxt.Cursym = s + if s.Sect != nil { + s.Value += int64(s.Sect.Vaddr) + } + for sub := s.Sub; sub != nil; sub = sub.Sub { + sub.Value += s.Value + } + } + + for sym := dwarfp; sym != nil; sym = sym.Next { Ctxt.Cursym = sym if sym.Sect != nil { sym.Value += int64(sym.Sect.Vaddr) } - for sub = sym.Sub; sub != nil; sub = sub.Sub { + for sub := sym.Sub; sub != nil; sub = sub.Sub { sub.Value += sym.Value } } @@ -1892,6 +2095,11 @@ func address() { s.Value = int64(sectSym.Sect.Vaddr + 16) } + types := relrodata + if types == nil { + types = rodata + } + xdefine("runtime.text", obj.STEXT, int64(text.Vaddr)) xdefine("runtime.etext", obj.STEXT, int64(text.Vaddr+text.Length)) if HEADTYPE == obj.Hwindows { @@ -1899,6 +2107,8 @@ func address() { } xdefine("runtime.rodata", obj.SRODATA, int64(rodata.Vaddr)) xdefine("runtime.erodata", obj.SRODATA, int64(rodata.Vaddr+rodata.Length)) + xdefine("runtime.types", obj.SRODATA, int64(types.Vaddr)) + xdefine("runtime.etypes", obj.SRODATA, int64(types.Vaddr+types.Length)) xdefine("runtime.typelink", obj.SRODATA, int64(typelink.Vaddr)) xdefine("runtime.etypelink", obj.SRODATA, int64(typelink.Vaddr+typelink.Length)) xdefine("runtime.itablink", obj.SRODATA, int64(itablink.Vaddr)) diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index 56c4370bcc..aaed6cde21 100644 --- a/src/cmd/link/internal/ld/deadcode.go +++ b/src/cmd/link/internal/ld/deadcode.go @@ -6,6 +6,7 @@ package ld import ( "cmd/internal/obj" + "cmd/internal/sys" "fmt" "strings" "unicode" @@ -18,7 +19,7 @@ import ( // // This flood fill is wrapped in logic for pruning unused methods. // All methods are mentioned by relocations on their receiver's *rtype. -// These relocations are specially defined as R_METHOD by the compiler +// These relocations are specially defined as R_METHODOFF by the compiler // so we can detect and manipulated them here. // // There are three ways a method of a reachable type can be invoked: @@ -99,7 +100,7 @@ func deadcode(ctxt *Link) { d.flood() } - // Remove all remaining unreached R_METHOD relocations. + // Remove all remaining unreached R_METHODOFF relocations. for _, m := range d.markableMethods { for _, r := range m.r { d.cleanupReloc(r) @@ -118,25 +119,13 @@ func deadcode(ctxt *Link) { } // Remove dead text but keep file information (z symbols). - var last *LSym - for s := ctxt.Textp; s != nil; s = s.Next { - if !s.Attr.Reachable() { - continue + textp := make([]*LSym, 0, len(ctxt.Textp)) + for _, s := range ctxt.Textp { + if s.Attr.Reachable() { + textp = append(textp, s) } - if last == nil { - ctxt.Textp = s - } else { - last.Next = s - } - last = s - } - if last == nil { - ctxt.Textp = nil - ctxt.Etextp = nil - } else { - last.Next = nil - ctxt.Etextp = last } + ctxt.Textp = textp } var markextra = []string{ @@ -166,12 +155,10 @@ var markextra = []string{ type methodref struct { m methodsig src *LSym // receiver type symbol - r [3]*Reloc // R_METHOD relocations to fields of runtime.method + r [3]*Reloc // R_METHODOFF relocations to fields of runtime.method } -func (m methodref) mtyp() *LSym { return m.r[0].Sym } -func (m methodref) ifn() *LSym { return m.r[1].Sym } -func (m methodref) tfn() *LSym { return m.r[2].Sym } +func (m methodref) ifn() *LSym { return m.r[1].Sym } func (m methodref) isExported() bool { for _, r := range m.m { @@ -191,7 +178,7 @@ type deadcodepass struct { func (d *deadcodepass) cleanupReloc(r *Reloc) { if r.Sym.Attr.Reachable() { - r.Type = obj.R_ADDR + r.Type = obj.R_ADDROFF } else { if Debug['v'] > 1 { fmt.Fprintf(d.ctxt.Bso, "removing method %s\n", r.Sym.Name) @@ -209,6 +196,13 @@ func (d *deadcodepass) mark(s, parent *LSym) { if s.Attr.ReflectMethod() { d.reflectMethod = true } + if flag_dumpdep { + p := "_" + if parent != nil { + p = parent.Name + } + fmt.Printf("%s -> %s\n", p, s.Name) + } s.Attr |= AttrReachable s.Reachparent = parent d.markQueue = append(d.markQueue, s) @@ -218,7 +212,7 @@ func (d *deadcodepass) mark(s, parent *LSym) { func (d *deadcodepass) markMethod(m methodref) { for _, r := range m.r { d.mark(r.Sym, m.src) - r.Type = obj.R_ADDR + r.Type = obj.R_ADDROFF } } @@ -227,7 +221,7 @@ func (d *deadcodepass) markMethod(m methodref) { func (d *deadcodepass) init() { var names []string - if Thearch.Thechar == '5' { + if SysArch.Family == sys.ARM { // mark some functions that are only referenced after linker code editing if d.ctxt.Goarm == 5 { names = append(names, "_sfloat") @@ -273,9 +267,12 @@ func (d *deadcodepass) flood() { if Debug['v'] > 1 { fmt.Fprintf(d.ctxt.Bso, "marktext %s\n", s.Name) } - for _, a := range s.Autom { - d.mark(a.Gotype, s) + if s.FuncInfo != nil { + for _, a := range s.FuncInfo.Autom { + d.mark(a.Gotype, s) + } } + } if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' { @@ -289,14 +286,14 @@ func (d *deadcodepass) flood() { } } - mpos := 0 // 0-3, the R_METHOD relocs of runtime.uncommontype + mpos := 0 // 0-3, the R_METHODOFF relocs of runtime.uncommontype var methods []methodref for i := 0; i < len(s.R); i++ { r := &s.R[i] if r.Sym == nil { continue } - if r.Type != obj.R_METHOD { + if r.Type != obj.R_METHODOFF { d.mark(r.Sym, s) continue } @@ -333,9 +330,9 @@ func (d *deadcodepass) flood() { d.markableMethods = append(d.markableMethods, methods...) } - if s.Pcln != nil { - for i := range s.Pcln.Funcdata { - d.mark(s.Pcln.Funcdata[i], s) + if s.FuncInfo != nil { + for i := range s.FuncInfo.Funcdata { + d.mark(s.FuncInfo.Funcdata[i], s) } } d.mark(s.Gotype, s) diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index 0a6bf094aa..551ff802d7 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -7,6 +7,7 @@ package ld import ( "bytes" "cmd/internal/obj" + "cmd/internal/sys" "debug/elf" "fmt" ) @@ -15,10 +16,22 @@ import ( // ../../runtime/type.go, or more specifically, with what // ../gc/reflect.c stuffs in these. +// tflag is documented in reflect/type.go. +// +// tflag values must be kept in sync with copies in: +// cmd/compile/internal/gc/reflect.go +// cmd/link/internal/ld/decodesym.go +// reflect/type.go +// runtime/type.go +const ( + tflagUncommon = 1 << 0 + tflagExtraStar = 1 << 1 +) + func decode_reloc(s *LSym, off int32) *Reloc { - for i := 0; i < len(s.R); i++ { + for i := range s.R { if s.R[i].Off == off { - return &s.R[i:][0] + return &s.R[i] } } return nil @@ -46,39 +59,33 @@ func decode_inuxi(p []byte, sz int) uint64 { } } -func commonsize() int { return 6*Thearch.Ptrsize + 8 } // runtime._type -func structfieldSize() int { return 3 * Thearch.Ptrsize } // runtime.structfield -func uncommonSize() int { return 2*Thearch.Ptrsize + 2*Thearch.Intsize } // runtime.uncommontype +func commonsize() int { return 4*SysArch.PtrSize + 8 + 8 } // runtime._type +func structfieldSize() int { return 3 * SysArch.PtrSize } // runtime.structfield +func uncommonSize() int { return 4 + 2 + 2 } // runtime.uncommontype // Type.commonType.kind func decodetype_kind(s *LSym) uint8 { - return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindMask) // 0x13 / 0x1f -} - -// Type.commonType.kind -func decodetype_noptr(s *LSym) uint8 { - return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindNoPointers) // 0x13 / 0x1f + return s.P[2*SysArch.PtrSize+7] & obj.KindMask // 0x13 / 0x1f } // Type.commonType.kind func decodetype_usegcprog(s *LSym) uint8 { - return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindGCProg) // 0x13 / 0x1f + return s.P[2*SysArch.PtrSize+7] & obj.KindGCProg // 0x13 / 0x1f } // Type.commonType.size func decodetype_size(s *LSym) int64 { - return int64(decode_inuxi(s.P, Thearch.Ptrsize)) // 0x8 / 0x10 + return int64(decode_inuxi(s.P, SysArch.PtrSize)) // 0x8 / 0x10 } // Type.commonType.ptrdata func decodetype_ptrdata(s *LSym) int64 { - return int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Ptrsize)) // 0x8 / 0x10 + return int64(decode_inuxi(s.P[SysArch.PtrSize:], SysArch.PtrSize)) // 0x8 / 0x10 } // Type.commonType.tflag func decodetype_hasUncommon(s *LSym) bool { - const tflagUncommon = 1 // see ../../../../reflect/type.go:/^type.tflag - return s.P[2*Thearch.Ptrsize+4]&tflagUncommon != 0 + return s.P[2*SysArch.PtrSize+4]&tflagUncommon != 0 } // Find the elf.Section of a given shared library that contains a given address. @@ -112,11 +119,11 @@ func decodetype_gcprog(s *LSym) []byte { Exitf("cannot find gcprog for %s", s.Name) return nil } - return decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize)).P + return decode_reloc_sym(s, 2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize)).P } func decodetype_gcprog_shlib(s *LSym) uint64 { - if Thearch.Thechar == '7' { + if SysArch.Family == sys.ARM64 { for _, shlib := range Ctxt.Shlibs { if shlib.Path == s.File { return shlib.gcdata_addresses[s] @@ -124,7 +131,7 @@ func decodetype_gcprog_shlib(s *LSym) uint64 { } return 0 } - return decode_inuxi(s.P[2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize):], Thearch.Ptrsize) + return decode_inuxi(s.P[2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize):], SysArch.PtrSize) } func decodetype_gcmask(s *LSym) []byte { @@ -133,14 +140,14 @@ func decodetype_gcmask(s *LSym) []byte { ptrdata := decodetype_ptrdata(s) sect := findShlibSection(s.File, addr) if sect != nil { - r := make([]byte, ptrdata/int64(Thearch.Ptrsize)) + r := make([]byte, ptrdata/int64(SysArch.PtrSize)) sect.ReadAt(r, int64(addr-sect.Addr)) return r } Exitf("cannot find gcmask for %s", s.Name) return nil } - mask := decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize)) + mask := decode_reloc_sym(s, 2*int32(SysArch.PtrSize)+8+1*int32(SysArch.PtrSize)) return mask.P } @@ -150,7 +157,7 @@ func decodetype_arrayelem(s *LSym) *LSym { } func decodetype_arraylen(s *LSym) int64 { - return int64(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Ptrsize)) + return int64(decode_inuxi(s.P[commonsize()+2*SysArch.PtrSize:], SysArch.PtrSize)) } // Type.PtrType.elem @@ -164,7 +171,7 @@ func decodetype_mapkey(s *LSym) *LSym { } func decodetype_mapvalue(s *LSym) *LSym { - return decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)) // 0x20 / 0x38 + return decode_reloc_sym(s, int32(commonsize())+int32(SysArch.PtrSize)) // 0x20 / 0x38 } // Type.ChanType.elem @@ -188,13 +195,13 @@ func decodetype_funcoutcount(s *LSym) int { func decodetype_funcintype(s *LSym, i int) *LSym { uadd := commonsize() + 4 - if Thearch.Ptrsize == 8 { + if SysArch.PtrSize == 8 { uadd += 4 } if decodetype_hasUncommon(s) { uadd += uncommonSize() } - return decode_reloc_sym(s, int32(uadd+i*Thearch.Ptrsize)) + return decode_reloc_sym(s, int32(uadd+i*SysArch.PtrSize)) } func decodetype_funcouttype(s *LSym, i int) *LSym { @@ -203,11 +210,11 @@ func decodetype_funcouttype(s *LSym, i int) *LSym { // Type.StructType.fields.Slice::length func decodetype_structfieldcount(s *LSym) int { - return int(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Intsize)) + return int(decode_inuxi(s.P[commonsize()+2*SysArch.PtrSize:], SysArch.IntSize)) } func decodetype_structfieldarrayoff(s *LSym, i int) int { - off := commonsize() + 2*Thearch.Ptrsize + 2*Thearch.Intsize + off := commonsize() + 2*SysArch.PtrSize + 2*SysArch.IntSize if decodetype_hasUncommon(s) { off += uncommonSize() } @@ -215,17 +222,13 @@ func decodetype_structfieldarrayoff(s *LSym, i int) int { return off } -func decodetype_stringptr(s *LSym, off int) string { - s = decode_reloc_sym(s, int32(off)) - if s == nil { - return "" - } - r := decode_reloc(s, 0) // s has a pointer to the string data at offset 0 - if r == nil { // shouldn't happen. - return "" +// decodetype_str returns the contents of an rtype's str field (a nameOff). +func decodetype_str(s *LSym) string { + str := decodetype_name(s, 4*SysArch.PtrSize+8) + if s.P[2*SysArch.PtrSize+4]&tflagExtraStar != 0 { + return str[1:] } - strlen := int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Intsize)) - return string(r.Sym.P[r.Add : r.Add+strlen]) + return str } // decodetype_name decodes the name from a reflect.name. @@ -236,9 +239,8 @@ func decodetype_name(s *LSym, off int) string { } data := r.Sym.P - namelen := int(uint16(data[1]<<8) | uint16(data[2])) + namelen := int(uint16(data[1])<<8 | uint16(data[2])) return string(data[3 : 3+namelen]) - } func decodetype_structfieldname(s *LSym, i int) string { @@ -248,17 +250,17 @@ func decodetype_structfieldname(s *LSym, i int) string { func decodetype_structfieldtype(s *LSym, i int) *LSym { off := decodetype_structfieldarrayoff(s, i) - return decode_reloc_sym(s, int32(off+Thearch.Ptrsize)) + return decode_reloc_sym(s, int32(off+SysArch.PtrSize)) } func decodetype_structfieldoffs(s *LSym, i int) int64 { off := decodetype_structfieldarrayoff(s, i) - return int64(decode_inuxi(s.P[off+2*Thearch.Ptrsize:], Thearch.Intsize)) + return int64(decode_inuxi(s.P[off+2*SysArch.PtrSize:], SysArch.IntSize)) } // InterfaceType.methods.length func decodetype_ifacemethodcount(s *LSym) int64 { - return int64(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Intsize)) + return int64(decode_inuxi(s.P[commonsize()+2*SysArch.PtrSize:], SysArch.IntSize)) } // methodsig is a fully qualified typed method signature, like @@ -279,8 +281,9 @@ const ( ) // decode_methodsig decodes an array of method signature information. -// Each element of the array is size bytes. The first word is a -// reflect.name for the name, the second word is a *rtype for the funcType. +// Each element of the array is size bytes. The first 4 bytes is a +// nameOff for the method name, and the next 4 bytes is a typeOff for +// the function type. // // Conveniently this is the layout of both runtime.method and runtime.imethod. func decode_methodsig(s *LSym, off, size, count int) []methodsig { @@ -288,7 +291,7 @@ func decode_methodsig(s *LSym, off, size, count int) []methodsig { var methods []methodsig for i := 0; i < count; i++ { buf.WriteString(decodetype_name(s, off)) - mtypSym := decode_reloc_sym(s, int32(off+Thearch.Ptrsize)) + mtypSym := decode_reloc_sym(s, int32(off+4)) buf.WriteRune('(') inCount := decodetype_funcincount(mtypSym) @@ -319,7 +322,7 @@ func decodetype_ifacemethods(s *LSym) []methodsig { if decodetype_kind(s)&kindMask != kindInterface { panic(fmt.Sprintf("symbol %q is not an interface", s.Name)) } - r := decode_reloc(s, int32(commonsize()+Thearch.Ptrsize)) + r := decode_reloc(s, int32(commonsize()+SysArch.PtrSize)) if r == nil { return nil } @@ -328,7 +331,7 @@ func decodetype_ifacemethods(s *LSym) []methodsig { } off := int(r.Add) // array of reflect.imethod values numMethods := int(decodetype_ifacemethodcount(s)) - sizeofIMethod := 2 * Thearch.Ptrsize + sizeofIMethod := 4 + 4 return decode_methodsig(s, off, sizeofIMethod, numMethods) } @@ -339,31 +342,28 @@ func decodetype_methods(s *LSym) []methodsig { off := commonsize() // reflect.rtype switch decodetype_kind(s) & kindMask { case kindStruct: // reflect.structType - off += 2*Thearch.Ptrsize + 2*Thearch.Intsize + off += 2*SysArch.PtrSize + 2*SysArch.IntSize case kindPtr: // reflect.ptrType - off += Thearch.Ptrsize + off += SysArch.PtrSize case kindFunc: // reflect.funcType - off += Thearch.Ptrsize // 4 bytes, pointer aligned + off += SysArch.PtrSize // 4 bytes, pointer aligned case kindSlice: // reflect.sliceType - off += Thearch.Ptrsize + off += SysArch.PtrSize case kindArray: // reflect.arrayType - off += 3 * Thearch.Ptrsize + off += 3 * SysArch.PtrSize case kindChan: // reflect.chanType - off += 2 * Thearch.Ptrsize + off += 2 * SysArch.PtrSize case kindMap: // reflect.mapType - off += 4*Thearch.Ptrsize + 8 + off += 4*SysArch.PtrSize + 8 case kindInterface: // reflect.interfaceType - off += Thearch.Ptrsize + 2*Thearch.Intsize + off += SysArch.PtrSize + 2*SysArch.IntSize default: // just Sizeof(rtype) } - numMethods := int(decode_inuxi(s.P[off+2*Thearch.Ptrsize:], Thearch.Intsize)) - r := decode_reloc(s, int32(off+Thearch.Ptrsize)) - if r.Sym != s { - panic(fmt.Sprintf("method slice pointer in %s leads to a different symbol %s", s, r.Sym)) - } - off = int(r.Add) // array of reflect.method values - sizeofMethod := 4 * Thearch.Ptrsize // sizeof reflect.method in program - return decode_methodsig(s, off, sizeofMethod, numMethods) + mcount := int(decode_inuxi(s.P[off+4:], 2)) + moff := int(decode_inuxi(s.P[off+4+2:], 2)) + off += moff // offset to array of reflect.method values + const sizeofMethod = 4 * 4 // sizeof reflect.method in program + return decode_methodsig(s, off, sizeofMethod, mcount) } diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index fd177cfef0..bf1a7e74c1 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -17,97 +17,34 @@ package ld import ( "cmd/internal/obj" "fmt" + "log" "os" "strings" ) +const infoprefix = "go.dwarf.info." + /* * Offsets and sizes of the debug_* sections in the cout file. */ -var abbrevo int64 - -var abbrevsize int64 - var abbrevsym *LSym - -var abbrevsympos int64 - -var lineo int64 - -var linesize int64 - -var linesym *LSym - -var linesympos int64 - -var infoo int64 // also the base for DWDie->offs and reference attributes. - -var infosize int64 - -var infosym *LSym - -var infosympos int64 - -var frameo int64 - -var framesize int64 - -var framesym *LSym - -var framesympos int64 - -var pubnameso int64 - -var pubnamessize int64 - -var pubtypeso int64 - -var pubtypessize int64 - -var arangeso int64 - -var arangessize int64 - -var gdbscripto int64 - -var gdbscriptsize int64 - -var infosec *LSym - -var inforeloco int64 - -var inforelocsize int64 - var arangessec *LSym - -var arangesreloco int64 - -var arangesrelocsize int64 - -var linesec *LSym - -var linereloco int64 - -var linerelocsize int64 - var framesec *LSym - -var framereloco int64 - -var framerelocsize int64 +var infosec *LSym +var linesec *LSym var gdbscript string /* * Basic I/O */ -func addrput(addr int64) { - switch Thearch.Ptrsize { +func addrput(s *LSym, addr int64) { + switch SysArch.PtrSize { case 4: - Thearch.Lput(uint32(addr)) + Adduint32(Ctxt, s, uint32(addr)) case 8: - Thearch.Vput(uint64(addr)) + Adduint64(Ctxt, s, uint64(addr)) } } @@ -144,14 +81,14 @@ func appendSleb128(b []byte, v int64) []byte { var encbuf [10]byte -func uleb128put(v int64) { +func uleb128put(s *LSym, v int64) { b := appendUleb128(encbuf[:0], uint64(v)) - Cwrite(b) + Addbytes(Ctxt, s, b) } -func sleb128put(v int64) { +func sleb128put(s *LSym, v int64) { b := appendSleb128(encbuf[:0], v) - Cwrite(b) + Addbytes(Ctxt, s, b) } /* @@ -462,24 +399,29 @@ var abbrevs = [DW_NABRV]DWAbbrev{ }, } -func writeabbrev() { - abbrevo = Cpos() +var dwarfp *LSym + +func writeabbrev() *LSym { + s := Linklookup(Ctxt, ".debug_abbrev", 0) + s.Type = obj.SDWARFSECT + abbrevsym = s + for i := 1; i < DW_NABRV; i++ { // See section 7.5.3 - uleb128put(int64(i)) + uleb128put(s, int64(i)) - uleb128put(int64(abbrevs[i].tag)) - Cput(abbrevs[i].children) + uleb128put(s, int64(abbrevs[i].tag)) + Adduint8(Ctxt, s, abbrevs[i].children) for _, f := range abbrevs[i].attr { - uleb128put(int64(f.attr)) - uleb128put(int64(f.form)) + uleb128put(s, int64(f.attr)) + uleb128put(s, int64(f.form)) } - uleb128put(0) - uleb128put(0) + uleb128put(s, 0) + uleb128put(s, 0) } - Cput(0) - abbrevsize = Cpos() - abbrevo + Adduint8(Ctxt, s, 0) + return s } /* @@ -504,10 +446,7 @@ type DWDie struct { link *DWDie child *DWDie attr *DWAttr - // offset into .debug_info section, i.e relative to - // infoo. only valid after call to putdie() - offs int64 - hash map[string]*DWDie // optional index of DWAttr by name, enabled by mkindex() + sym *LSym } /* @@ -556,9 +495,8 @@ func getattr(die *DWDie, attr uint16) *DWAttr { } // Every DIE has at least a DW_AT_name attribute (but it will only be -// written out if it is listed in the abbrev). If its parent is -// keeping an index, the new DIE will be inserted there. -func newdie(parent *DWDie, abbrev int, name string) *DWDie { +// written out if it is listed in the abbrev). +func newdie(parent *DWDie, abbrev int, name string, version int) *DWDie { die := new(DWDie) die.abbrev = abbrev die.link = parent.child @@ -566,17 +504,17 @@ func newdie(parent *DWDie, abbrev int, name string) *DWDie { newattr(die, DW_AT_name, DW_CLS_STRING, int64(len(name)), name) - if parent.hash != nil { - parent.hash[name] = die + if name != "" && (abbrev <= DW_ABRV_VARIABLE || abbrev >= DW_ABRV_NULLTYPE) { + if abbrev != DW_ABRV_VARIABLE || version == 0 { + die.sym = Linklookup(Ctxt, infoprefix+name, version) + die.sym.Attr |= AttrHidden + die.sym.Type = obj.SDWARFINFO + } } return die } -func mkindex(die *DWDie) { - die.hash = make(map[string]*DWDie) -} - func walktypedef(die *DWDie) *DWDie { // Resolve typedef if present. if die.abbrev == DW_ABRV_TYPEDECL { @@ -590,159 +528,157 @@ func walktypedef(die *DWDie) *DWDie { return die } +func walksymtypedef(s *LSym) *LSym { + if t := Linkrlookup(Ctxt, s.Name+".def", int(s.Version)); t != nil { + return t + } + return s +} + // Find child by AT_name using hashtable if available or linear scan // if not. -func find(die *DWDie, name string) *DWDie { +func findchild(die *DWDie, name string) *DWDie { var prev *DWDie for ; die != prev; prev, die = die, walktypedef(die) { - if die.hash == nil { - for a := die.child; a != nil; a = a.link { - if name == getattr(a, DW_AT_name).data { - return a - } + for a := die.child; a != nil; a = a.link { + if name == getattr(a, DW_AT_name).data { + return a } - continue - } - if a := die.hash[name]; a != nil { - return a } + continue } return nil } -func mustFind(die *DWDie, name string) *DWDie { - r := find(die, name) +// Used to avoid string allocation when looking up dwarf symbols +var prefixBuf = []byte(infoprefix) + +func find(name string) *LSym { + n := append(prefixBuf, name...) + // The string allocation below is optimized away because it is only used in a map lookup. + s := Linkrlookup(Ctxt, string(n), 0) + prefixBuf = n[:len(infoprefix)] + return s +} + +func mustFind(name string) *LSym { + r := find(name) if r == nil { - Exitf("dwarf find: %s %p has no %s", getattr(die, DW_AT_name).data, die, name) + Exitf("dwarf find: cannot find %s", name) } return r } -func adddwarfrel(sec *LSym, sym *LSym, offsetbase int64, siz int, addend int64) { - r := Addrel(sec) - r.Sym = sym - r.Xsym = sym - r.Off = int32(Cpos() - offsetbase) - r.Siz = uint8(siz) - r.Type = obj.R_ADDR - r.Add = addend - r.Xadd = addend - if Iself && Thearch.Thechar == '6' { - addend = 0 - } - if HEADTYPE == obj.Hdarwin { - addend += sym.Value - } - switch siz { - case 4: - Thearch.Lput(uint32(addend)) - - case 8: - Thearch.Vput(uint64(addend)) - +func adddwarfref(ctxt *Link, s *LSym, t *LSym, size int) int64 { + var result int64 + switch size { default: - Diag("bad size in adddwarfrel") + Diag("invalid size %d in adddwarfref\n", size) + fallthrough + case SysArch.PtrSize: + result = Addaddr(ctxt, s, t) + case 4: + result = addaddrplus4(ctxt, s, t, 0) } + r := &s.R[len(s.R)-1] + r.Type = obj.R_DWARFREF + return result } -func newrefattr(die *DWDie, attr uint16, ref *DWDie) *DWAttr { +func newrefattr(die *DWDie, attr uint16, ref *LSym) *DWAttr { if ref == nil { return nil } return newattr(die, attr, DW_CLS_REFERENCE, 0, ref) } -var fwdcount int - -func putattr(abbrev int, form int, cls int, value int64, data interface{}) { +func putattr(s *LSym, abbrev int, form int, cls int, value int64, data interface{}) { switch form { case DW_FORM_addr: // address if Linkmode == LinkExternal { value -= (data.(*LSym)).Value - adddwarfrel(infosec, data.(*LSym), infoo, Thearch.Ptrsize, value) + Addaddrplus(Ctxt, s, data.(*LSym), value) break } - addrput(value) + addrput(s, value) case DW_FORM_block1: // block if cls == DW_CLS_ADDRESS { - Cput(uint8(1 + Thearch.Ptrsize)) - Cput(DW_OP_addr) - if Linkmode == LinkExternal { - value -= (data.(*LSym)).Value - adddwarfrel(infosec, data.(*LSym), infoo, Thearch.Ptrsize, value) - break - } - - addrput(value) + Adduint8(Ctxt, s, uint8(1+SysArch.PtrSize)) + Adduint8(Ctxt, s, DW_OP_addr) + Addaddr(Ctxt, s, data.(*LSym)) break } value &= 0xff - Cput(uint8(value)) + Adduint8(Ctxt, s, uint8(value)) p := data.([]byte) for i := 0; int64(i) < value; i++ { - Cput(uint8(p[i])) + Adduint8(Ctxt, s, p[i]) } case DW_FORM_block2: // block value &= 0xffff - Thearch.Wput(uint16(value)) + Adduint16(Ctxt, s, uint16(value)) p := data.([]byte) for i := 0; int64(i) < value; i++ { - Cput(uint8(p[i])) + Adduint8(Ctxt, s, p[i]) } case DW_FORM_block4: // block value &= 0xffffffff - Thearch.Lput(uint32(value)) + Adduint32(Ctxt, s, uint32(value)) p := data.([]byte) for i := 0; int64(i) < value; i++ { - Cput(uint8(p[i])) + Adduint8(Ctxt, s, p[i]) } case DW_FORM_block: // block - uleb128put(value) + uleb128put(s, value) p := data.([]byte) for i := 0; int64(i) < value; i++ { - Cput(uint8(p[i])) + Adduint8(Ctxt, s, p[i]) } case DW_FORM_data1: // constant - Cput(uint8(value)) + Adduint8(Ctxt, s, uint8(value)) case DW_FORM_data2: // constant - Thearch.Wput(uint16(value)) + Adduint16(Ctxt, s, uint16(value)) case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr if Linkmode == LinkExternal && cls == DW_CLS_PTR { - adddwarfrel(infosec, linesym, infoo, 4, value) + adddwarfref(Ctxt, s, linesec, 4) break } - Thearch.Lput(uint32(value)) + Adduint32(Ctxt, s, uint32(value)) case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr - Thearch.Vput(uint64(value)) + Adduint64(Ctxt, s, uint64(value)) case DW_FORM_sdata: // constant - sleb128put(value) + sleb128put(s, value) case DW_FORM_udata: // constant - uleb128put(value) + uleb128put(s, value) case DW_FORM_string: // string - strnput(data.(string), int(value+1)) + str := data.(string) + Addstring(s, str) + for i := int64(len(str)); i < value; i++ { + Adduint8(Ctxt, s, 0) + } case DW_FORM_flag: // flag if value != 0 { - Cput(1) + Adduint8(Ctxt, s, 1) } else { - Cput(0) + Adduint8(Ctxt, s, 0) } // In DWARF 2 (which is what we claim to generate), @@ -752,22 +688,14 @@ func putattr(abbrev int, form int, cls int, value int64, data interface{}) { case DW_FORM_ref_addr: // reference to a DIE in the .info section if data == nil { Diag("dwarf: null reference in %d", abbrev) - if Thearch.Ptrsize == 8 { - Thearch.Vput(0) // invalid dwarf, gdb will complain. + if SysArch.PtrSize == 8 { + Adduint64(Ctxt, s, 0) // invalid dwarf, gdb will complain. } else { - Thearch.Lput(0) // invalid dwarf, gdb will complain. + Adduint32(Ctxt, s, 0) // invalid dwarf, gdb will complain. } } else { - off := (data.(*DWDie)).offs - if off == 0 { - fwdcount++ - } - if Linkmode == LinkExternal { - adddwarfrel(infosec, infosym, infoo, Thearch.Ptrsize, off) - break - } - - addrput(off) + dsym := data.(*LSym) + adddwarfref(Ctxt, s, dsym, SysArch.PtrSize) } case DW_FORM_ref1, // reference within the compilation unit @@ -786,34 +714,45 @@ func putattr(abbrev int, form int, cls int, value int64, data interface{}) { // Note that we can (and do) add arbitrary attributes to a DIE, but // only the ones actually listed in the Abbrev will be written out. -func putattrs(abbrev int, attr *DWAttr) { +func putattrs(s *LSym, abbrev int, attr *DWAttr) { Outer: for _, f := range abbrevs[abbrev].attr { for ap := attr; ap != nil; ap = ap.link { if ap.atr == f.attr { - putattr(abbrev, int(f.form), int(ap.cls), ap.value, ap.data) + putattr(s, abbrev, int(f.form), int(ap.cls), ap.value, ap.data) continue Outer } } - putattr(abbrev, int(f.form), 0, 0, nil) + putattr(s, abbrev, int(f.form), 0, 0, nil) } } -func putdies(die *DWDie) { +func putdies(prev *LSym, die *DWDie) *LSym { for ; die != nil; die = die.link { - putdie(die) + prev = putdie(prev, die) } + Adduint8(Ctxt, prev, 0) + return prev } -func putdie(die *DWDie) { - die.offs = Cpos() - infoo - uleb128put(int64(die.abbrev)) - putattrs(die.abbrev, die.attr) +func putdie(prev *LSym, die *DWDie) *LSym { + s := die.sym + if s == nil { + s = prev + } else { + if s.Attr.OnList() { + log.Fatalf("symbol %s listed multiple times", s.Name) + } + s.Attr |= AttrOnList + prev.Next = s + } + uleb128put(s, int64(die.abbrev)) + putattrs(s, die.abbrev, die.attr) if abbrevs[die.abbrev].children != 0 { - putdies(die.child) - Cput(0) + return putdies(s, die.child) } + return s } func reverselist(list **DWDie) { @@ -880,44 +819,50 @@ func dotypedef(parent *DWDie, name string, def *DWDie) { Diag("dwarf: bad def in dotypedef") } + def.sym = Linklookup(Ctxt, def.sym.Name+".def", 0) + def.sym.Attr |= AttrHidden + def.sym.Type = obj.SDWARFINFO + // The typedef entry must be created after the def, // so that future lookups will find the typedef instead // of the real definition. This hooks the typedef into any // circular definition loops, so that gdb can understand them. - die := newdie(parent, DW_ABRV_TYPEDECL, name) + die := newdie(parent, DW_ABRV_TYPEDECL, name, 0) - newrefattr(die, DW_AT_type, def) + newrefattr(die, DW_AT_type, def.sym) } // Define gotype, for composite ones recurse into constituents. -func defgotype(gotype *LSym) *DWDie { +func defgotype(gotype *LSym) *LSym { if gotype == nil { - return mustFind(&dwtypes, "<unspecified>") + return mustFind("<unspecified>") } if !strings.HasPrefix(gotype.Name, "type.") { Diag("dwarf: type name doesn't start with \"type.\": %s", gotype.Name) - return mustFind(&dwtypes, "<unspecified>") + return mustFind("<unspecified>") } name := gotype.Name[5:] // could also decode from Type.string - die := find(&dwtypes, name) + sdie := find(name) - if die != nil { - return die + if sdie != nil { + return sdie } - if false && Debug['v'] > 2 { - fmt.Printf("new type: %v\n", gotype) - } + return newtype(gotype).sym +} +func newtype(gotype *LSym) *DWDie { + name := gotype.Name[5:] // could also decode from Type.string kind := decodetype_kind(gotype) bytesize := decodetype_size(gotype) + var die *DWDie switch kind { case obj.KindBool: - die = newdie(&dwtypes, DW_ABRV_BASETYPE, name) + die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0) newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_boolean, 0) newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0) @@ -926,7 +871,7 @@ func defgotype(gotype *LSym) *DWDie { obj.KindInt16, obj.KindInt32, obj.KindInt64: - die = newdie(&dwtypes, DW_ABRV_BASETYPE, name) + die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0) newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_signed, 0) newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0) @@ -936,66 +881,69 @@ func defgotype(gotype *LSym) *DWDie { obj.KindUint32, obj.KindUint64, obj.KindUintptr: - die = newdie(&dwtypes, DW_ABRV_BASETYPE, name) + die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0) newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0) newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0) case obj.KindFloat32, obj.KindFloat64: - die = newdie(&dwtypes, DW_ABRV_BASETYPE, name) + die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0) newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_float, 0) newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0) case obj.KindComplex64, obj.KindComplex128: - die = newdie(&dwtypes, DW_ABRV_BASETYPE, name) + die = newdie(&dwtypes, DW_ABRV_BASETYPE, name, 0) newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_complex_float, 0) newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0) case obj.KindArray: - die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name) + die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name, 0) dotypedef(&dwtypes, name, die) newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0) s := decodetype_arrayelem(gotype) newrefattr(die, DW_AT_type, defgotype(s)) - fld := newdie(die, DW_ABRV_ARRAYRANGE, "range") + fld := newdie(die, DW_ABRV_ARRAYRANGE, "range", 0) // use actual length not upper bound; correct for 0-length arrays. newattr(fld, DW_AT_count, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0) - newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr")) + newrefattr(fld, DW_AT_type, mustFind("uintptr")) case obj.KindChan: - die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name) + die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name, 0) newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0) s := decodetype_chanelem(gotype) newrefattr(die, DW_AT_go_elem, defgotype(s)) + // Save elem type for synthesizechantypes. We could synthesize here + // but that would change the order of DIEs we output. + newrefattr(die, DW_AT_type, s) case obj.KindFunc: - die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name) + die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name, 0) dotypedef(&dwtypes, name, die) - newrefattr(die, DW_AT_type, mustFind(&dwtypes, "void")) + newrefattr(die, DW_AT_type, mustFind("void")) nfields := decodetype_funcincount(gotype) var fld *DWDie var s *LSym for i := 0; i < nfields; i++ { s = decodetype_funcintype(gotype, i) - fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:]) + fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0) newrefattr(fld, DW_AT_type, defgotype(s)) } if decodetype_funcdotdotdot(gotype) { - newdie(die, DW_ABRV_DOTDOTDOT, "...") + newdie(die, DW_ABRV_DOTDOTDOT, "...", 0) } nfields = decodetype_funcoutcount(gotype) for i := 0; i < nfields; i++ { s = decodetype_funcouttype(gotype, i) - fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:]) + fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:], 0) newrefattr(fld, DW_AT_type, defptrto(defgotype(s))) } case obj.KindInterface: - die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name) + die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name, 0) dotypedef(&dwtypes, name, die) newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0) nfields := int(decodetype_ifacemethodcount(gotype)) @@ -1008,31 +956,35 @@ func defgotype(gotype *LSym) *DWDie { newrefattr(die, DW_AT_type, defgotype(s)) case obj.KindMap: - die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name) + die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name, 0) s := decodetype_mapkey(gotype) newrefattr(die, DW_AT_go_key, defgotype(s)) s = decodetype_mapvalue(gotype) newrefattr(die, DW_AT_go_elem, defgotype(s)) + // Save gotype for use in synthesizemaptypes. We could synthesize here, + // but that would change the order of the DIEs. + newrefattr(die, DW_AT_type, gotype) case obj.KindPtr: - die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name) + die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name, 0) dotypedef(&dwtypes, name, die) s := decodetype_ptrelem(gotype) newrefattr(die, DW_AT_type, defgotype(s)) case obj.KindSlice: - die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name) + die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name, 0) dotypedef(&dwtypes, name, die) newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0) s := decodetype_arrayelem(gotype) - newrefattr(die, DW_AT_go_elem, defgotype(s)) + elem := defgotype(s) + newrefattr(die, DW_AT_go_elem, elem) case obj.KindString: - die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name) + die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name, 0) newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0) case obj.KindStruct: - die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name) + die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name, 0) dotypedef(&dwtypes, name, die) newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0) nfields := decodetype_structfieldcount(gotype) @@ -1045,32 +997,41 @@ func defgotype(gotype *LSym) *DWDie { if f == "" { f = s.Name[5:] // skip "type." } - fld = newdie(die, DW_ABRV_STRUCTFIELD, f) + fld = newdie(die, DW_ABRV_STRUCTFIELD, f, 0) newrefattr(fld, DW_AT_type, defgotype(s)) newmemberoffsetattr(fld, int32(decodetype_structfieldoffs(gotype, i))) } case obj.KindUnsafePointer: - die = newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, name) + die = newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, name, 0) default: Diag("dwarf: definition of unknown kind %d: %s", kind, gotype.Name) - die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name) - newrefattr(die, DW_AT_type, mustFind(&dwtypes, "<unspecified>")) + die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name, 0) + newrefattr(die, DW_AT_type, mustFind("<unspecified>")) } newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, int64(kind), 0) + if _, ok := prototypedies[gotype.Name]; ok { + prototypedies[gotype.Name] = die + } + return die } +func nameFromDIESym(dwtype *LSym) string { + return strings.TrimSuffix(dwtype.Name[len(infoprefix):], ".def") +} + // Find or construct *T given T. -func defptrto(dwtype *DWDie) *DWDie { - ptrname := fmt.Sprintf("*%s", getattr(dwtype, DW_AT_name).data) - die := find(&dwtypes, ptrname) +func defptrto(dwtype *LSym) *LSym { + ptrname := "*" + nameFromDIESym(dwtype) + die := find(ptrname) if die == nil { - die = newdie(&dwtypes, DW_ABRV_PTRTYPE, ptrname) - newrefattr(die, DW_AT_type, dwtype) + pdie := newdie(&dwtypes, DW_ABRV_PTRTYPE, ptrname, 0) + newrefattr(pdie, DW_AT_type, dwtype) + return pdie.sym } return die @@ -1084,7 +1045,7 @@ func copychildrenexcept(dst *DWDie, src *DWDie, except *DWDie) { if src == except { continue } - c := newdie(dst, src.abbrev, getattr(src, DW_AT_name).data.(string)) + c := newdie(dst, src.abbrev, getattr(src, DW_AT_name).data.(string), 0) for a := src.attr; a != nil; a = a.link { newattr(c, a.atr, int(a.cls), a.value, a.data) } @@ -1100,9 +1061,11 @@ func copychildren(dst *DWDie, src *DWDie) { // Search children (assumed to have DW_TAG_member) for the one named // field and set its DW_AT_type to dwtype -func substitutetype(structdie *DWDie, field string, dwtype *DWDie) { - child := mustFind(structdie, field) +func substitutetype(structdie *DWDie, field string, dwtype *LSym) { + child := findchild(structdie, field) if child == nil { + Exitf("dwarf substitutetype: %s does not have member %s", + getattr(structdie, DW_AT_name).data, field) return } @@ -1114,8 +1077,17 @@ func substitutetype(structdie *DWDie, field string, dwtype *DWDie) { } } +func findprotodie(name string) *DWDie { + die, ok := prototypedies[name] + if ok && die == nil { + defgotype(lookup_or_diag(name)) + die = prototypedies[name] + } + return die +} + func synthesizestringtypes(die *DWDie) { - prototype := walktypedef(defgotype(lookup_or_diag("type.runtime.stringStructDWARF"))) + prototype := walktypedef(findprotodie("type.runtime.stringStructDWARF")) if prototype == nil { return } @@ -1129,7 +1101,7 @@ func synthesizestringtypes(die *DWDie) { } func synthesizeslicetypes(die *DWDie) { - prototype := walktypedef(defgotype(lookup_or_diag("type.runtime.slice"))) + prototype := walktypedef(findprotodie("type.runtime.slice")) if prototype == nil { return } @@ -1139,7 +1111,7 @@ func synthesizeslicetypes(die *DWDie) { continue } copychildren(die, prototype) - elem := getattr(die, DW_AT_go_elem).data.(*DWDie) + elem := getattr(die, DW_AT_go_elem).data.(*LSym) substitutetype(die, "array", defptrto(elem)) } } @@ -1163,9 +1135,21 @@ const ( BucketSize = 8 ) +func mkinternaltype(abbrev int, typename, keyname, valname string, f func(*DWDie)) *LSym { + name := mkinternaltypename(typename, keyname, valname) + symname := infoprefix + name + s := Linkrlookup(Ctxt, symname, 0) + if s != nil { + return s + } + die := newdie(&dwtypes, abbrev, name, 0) + f(die) + return die.sym +} + func synthesizemaptypes(die *DWDie) { - hash := walktypedef(defgotype(lookup_or_diag("type.runtime.hmap"))) - bucket := walktypedef(defgotype(lookup_or_diag("type.runtime.bmap"))) + hash := walktypedef(findprotodie("type.runtime.hmap")) + bucket := walktypedef(findprotodie("type.runtime.bmap")) if hash == nil { return @@ -1175,97 +1159,92 @@ func synthesizemaptypes(die *DWDie) { if die.abbrev != DW_ABRV_MAPTYPE { continue } - - keytype := walktypedef(getattr(die, DW_AT_go_key).data.(*DWDie)) - valtype := walktypedef(getattr(die, DW_AT_go_elem).data.(*DWDie)) + gotype := getattr(die, DW_AT_type).data.(*LSym) + keytype := decodetype_mapkey(gotype) + valtype := decodetype_mapvalue(gotype) + keysize, valsize := decodetype_size(keytype), decodetype_size(valtype) + keytype, valtype = walksymtypedef(defgotype(keytype)), walksymtypedef(defgotype(valtype)) // compute size info like hashmap.c does. - keysize, valsize := Thearch.Ptrsize, Thearch.Ptrsize - a := getattr(keytype, DW_AT_byte_size) - if a != nil { - keysize = int(a.value) - } - a = getattr(valtype, DW_AT_byte_size) - if a != nil { - valsize = int(a.value) - } indirect_key, indirect_val := false, false if keysize > MaxKeySize { - keysize = Thearch.Ptrsize + keysize = int64(SysArch.PtrSize) indirect_key = true } if valsize > MaxValSize { - valsize = Thearch.Ptrsize + valsize = int64(SysArch.PtrSize) indirect_val = true } // Construct type to represent an array of BucketSize keys - dwhk := newdie(&dwtypes, DW_ABRV_ARRAYTYPE, mkinternaltypename("[]key", getattr(keytype, DW_AT_name).data.(string), "")) - - newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*int64(keysize), 0) - t := keytype - if indirect_key { - t = defptrto(keytype) - } - newrefattr(dwhk, DW_AT_type, t) - fld := newdie(dwhk, DW_ABRV_ARRAYRANGE, "size") - newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0) - newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr")) + keyname := nameFromDIESym(keytype) + dwhks := mkinternaltype(DW_ABRV_ARRAYTYPE, "[]key", keyname, "", func(dwhk *DWDie) { + newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*keysize, 0) + t := keytype + if indirect_key { + t = defptrto(keytype) + } + newrefattr(dwhk, DW_AT_type, t) + fld := newdie(dwhk, DW_ABRV_ARRAYRANGE, "size", 0) + newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0) + newrefattr(fld, DW_AT_type, mustFind("uintptr")) + }) // Construct type to represent an array of BucketSize values - dwhv := newdie(&dwtypes, DW_ABRV_ARRAYTYPE, mkinternaltypename("[]val", getattr(valtype, DW_AT_name).data.(string), "")) - - newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*int64(valsize), 0) - t = valtype - if indirect_val { - t = defptrto(valtype) - } - newrefattr(dwhv, DW_AT_type, t) - fld = newdie(dwhv, DW_ABRV_ARRAYRANGE, "size") - newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0) - newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr")) + valname := nameFromDIESym(valtype) + dwhvs := mkinternaltype(DW_ABRV_ARRAYTYPE, "[]val", valname, "", func(dwhv *DWDie) { + newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*valsize, 0) + t := valtype + if indirect_val { + t = defptrto(valtype) + } + newrefattr(dwhv, DW_AT_type, t) + fld := newdie(dwhv, DW_ABRV_ARRAYRANGE, "size", 0) + newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0) + newrefattr(fld, DW_AT_type, mustFind("uintptr")) + }) // Construct bucket<K,V> - dwhb := newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("bucket", getattr(keytype, DW_AT_name).data.(string), getattr(valtype, DW_AT_name).data.(string))) - - // Copy over all fields except the field "data" from the generic bucket. - // "data" will be replaced with keys/values below. - copychildrenexcept(dwhb, bucket, find(bucket, "data")) + dwhbs := mkinternaltype(DW_ABRV_STRUCTTYPE, "bucket", keyname, valname, func(dwhb *DWDie) { + // Copy over all fields except the field "data" from the generic + // bucket. "data" will be replaced with keys/values below. + copychildrenexcept(dwhb, bucket, findchild(bucket, "data")) - fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys") - newrefattr(fld, DW_AT_type, dwhk) - newmemberoffsetattr(fld, BucketSize) - fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "values") - newrefattr(fld, DW_AT_type, dwhv) - newmemberoffsetattr(fld, BucketSize+BucketSize*int32(keysize)) - fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "overflow") - newrefattr(fld, DW_AT_type, defptrto(dwhb)) - newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))) - if Thearch.Regsize > Thearch.Ptrsize { - fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "pad") - newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr")) - newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(Thearch.Ptrsize)) - } + fld := newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys", 0) + newrefattr(fld, DW_AT_type, dwhks) + newmemberoffsetattr(fld, BucketSize) + fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "values", 0) + newrefattr(fld, DW_AT_type, dwhvs) + newmemberoffsetattr(fld, BucketSize+BucketSize*int32(keysize)) + fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "overflow", 0) + newrefattr(fld, DW_AT_type, defptrto(dwhb.sym)) + newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))) + if SysArch.RegSize > SysArch.PtrSize { + fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "pad", 0) + newrefattr(fld, DW_AT_type, mustFind("uintptr")) + newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(SysArch.PtrSize)) + } - newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize+BucketSize*int64(keysize)+BucketSize*int64(valsize)+int64(Thearch.Regsize), 0) + newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize+BucketSize*keysize+BucketSize*valsize+int64(SysArch.RegSize), 0) + }) // Construct hash<K,V> - dwh := newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("hash", getattr(keytype, DW_AT_name).data.(string), getattr(valtype, DW_AT_name).data.(string))) - - copychildren(dwh, hash) - substitutetype(dwh, "buckets", defptrto(dwhb)) - substitutetype(dwh, "oldbuckets", defptrto(dwhb)) - newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hash, DW_AT_byte_size).value, nil) + dwhs := mkinternaltype(DW_ABRV_STRUCTTYPE, "hash", keyname, valname, func(dwh *DWDie) { + copychildren(dwh, hash) + substitutetype(dwh, "buckets", defptrto(dwhbs)) + substitutetype(dwh, "oldbuckets", defptrto(dwhbs)) + newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hash, DW_AT_byte_size).value, nil) + }) // make map type a pointer to hash<K,V> - newrefattr(die, DW_AT_type, defptrto(dwh)) + newrefattr(die, DW_AT_type, defptrto(dwhs)) } } func synthesizechantypes(die *DWDie) { - sudog := walktypedef(defgotype(lookup_or_diag("type.runtime.sudog"))) - waitq := walktypedef(defgotype(lookup_or_diag("type.runtime.waitq"))) - hchan := walktypedef(defgotype(lookup_or_diag("type.runtime.hchan"))) + sudog := walktypedef(findprotodie("type.runtime.sudog")) + waitq := walktypedef(findprotodie("type.runtime.waitq")) + hchan := walktypedef(findprotodie("type.runtime.hchan")) if sudog == nil || waitq == nil || hchan == nil { return } @@ -1276,42 +1255,41 @@ func synthesizechantypes(die *DWDie) { if die.abbrev != DW_ABRV_CHANTYPE { continue } - elemsize := Thearch.Ptrsize - elemtype := getattr(die, DW_AT_go_elem).data.(*DWDie) - a := getattr(elemtype, DW_AT_byte_size) - if a != nil { - elemsize = int(a.value) - } + elemgotype := getattr(die, DW_AT_type).data.(*LSym) + elemsize := decodetype_size(elemgotype) + elemname := elemgotype.Name[5:] + elemtype := walksymtypedef(defgotype(elemgotype)) // sudog<T> - dws := newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("sudog", getattr(elemtype, DW_AT_name).data.(string), "")) - - copychildren(dws, sudog) - substitutetype(dws, "elem", elemtype) - if elemsize > 8 { - elemsize -= 8 - } else { - elemsize = 0 - } - newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT, int64(sudogsize)+int64(elemsize), nil) + dwss := mkinternaltype(DW_ABRV_STRUCTTYPE, "sudog", elemname, "", func(dws *DWDie) { + copychildren(dws, sudog) + substitutetype(dws, "elem", elemtype) + if elemsize > 8 { + elemsize -= 8 + } else { + elemsize = 0 + } + newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT, int64(sudogsize)+elemsize, nil) + }) // waitq<T> - dww := newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("waitq", getattr(elemtype, DW_AT_name).data.(string), "")) + dwws := mkinternaltype(DW_ABRV_STRUCTTYPE, "waitq", elemname, "", func(dww *DWDie) { - copychildren(dww, waitq) - substitutetype(dww, "first", defptrto(dws)) - substitutetype(dww, "last", defptrto(dws)) - newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(waitq, DW_AT_byte_size).value, nil) + copychildren(dww, waitq) + substitutetype(dww, "first", defptrto(dwss)) + substitutetype(dww, "last", defptrto(dwss)) + newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(waitq, DW_AT_byte_size).value, nil) + }) // hchan<T> - dwh := newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("hchan", getattr(elemtype, DW_AT_name).data.(string), "")) + dwhs := mkinternaltype(DW_ABRV_STRUCTTYPE, "hchan", elemname, "", func(dwh *DWDie) { + copychildren(dwh, hchan) + substitutetype(dwh, "recvq", dwws) + substitutetype(dwh, "sendq", dwws) + newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hchan, DW_AT_byte_size).value, nil) + }) - copychildren(dwh, hchan) - substitutetype(dwh, "recvq", dww) - substitutetype(dwh, "sendq", dww) - newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hchan, DW_AT_byte_size).value, nil) - - newrefattr(die, DW_AT_type, defptrto(dwh)) + newrefattr(die, DW_AT_type, defptrto(dwhs)) } } @@ -1331,13 +1309,13 @@ func defdwsymb(sym *LSym, s string, t int, v int64, size int64, ver int, gotype var dv *DWDie - var dt *DWDie + var dt *LSym switch t { default: return case 'd', 'b', 'D', 'B': - dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s) + dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s, ver) newabslocexprattr(dv, v, sym) if ver == 0 { newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0) @@ -1367,8 +1345,8 @@ func finddebugruntimepath(s *LSym) { return } - for i := range s.Pcln.File { - f := s.Pcln.File[i] + for i := range s.FuncInfo.File { + f := s.FuncInfo.File[i] if i := strings.Index(f.Name, "runtime/runtime.go"); i >= 0 { gdbscript = f.Name[:i] + "runtime/runtime-gdb.py" break @@ -1386,23 +1364,23 @@ const ( OPCODE_BASE = 10 ) -func putpclcdelta(delta_pc int64, delta_lc int64) { +func putpclcdelta(s *LSym, delta_pc int64, delta_lc int64) { if LINE_BASE <= delta_lc && delta_lc < LINE_BASE+LINE_RANGE { var opcode int64 = OPCODE_BASE + (delta_lc - LINE_BASE) + (LINE_RANGE * delta_pc) if OPCODE_BASE <= opcode && opcode < 256 { - Cput(uint8(opcode)) + Adduint8(Ctxt, s, uint8(opcode)) return } } if delta_pc != 0 { - Cput(DW_LNS_advance_pc) - sleb128put(delta_pc) + Adduint8(Ctxt, s, DW_LNS_advance_pc) + sleb128put(s, delta_pc) } - Cput(DW_LNS_advance_line) - sleb128put(delta_lc) - Cput(DW_LNS_copy) + Adduint8(Ctxt, s, DW_LNS_advance_line) + sleb128put(s, delta_lc) + Adduint8(Ctxt, s, DW_LNS_copy) } func newcfaoffsetattr(die *DWDie, offs int32) { @@ -1428,26 +1406,6 @@ func mkvarname(name string, da int) string { * Walk prog table, emit line program and build DIE tree. */ -// flush previous compilation unit. -func flushunit(dwinfo *DWDie, pc int64, pcsym *LSym, unitstart int64, header_length int32) { - if dwinfo != nil && pc != 0 { - newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, pcsym) - } - - if unitstart >= 0 { - Cput(0) // start extended opcode - uleb128put(1) - Cput(DW_LNE_end_sequence) - - here := Cpos() - Cseek(unitstart) - Thearch.Lput(uint32(here - unitstart - 4)) // unit_length - Thearch.Wput(2) // dwarf version - Thearch.Lput(uint32(header_length)) // header length starting here - Cseek(here) - } -} - func getCompilationDir() string { if dir, err := os.Getwd(); err == nil { return dir @@ -1455,28 +1413,30 @@ func getCompilationDir() string { return "/" } -func writelines() { +func writelines(prev *LSym) *LSym { if linesec == nil { - linesec = Linklookup(Ctxt, ".dwarfline", 0) + linesec = Linklookup(Ctxt, ".debug_line", 0) } + linesec.Type = obj.SDWARFSECT linesec.R = linesec.R[:0] + ls := linesec + prev.Next = ls + unitstart := int64(-1) + headerstart := int64(-1) headerend := int64(-1) epc := int64(0) var epcs *LSym - lineo = Cpos() var dwinfo *DWDie - flushunit(dwinfo, epc, epcs, unitstart, int32(headerend-unitstart-10)) - unitstart = Cpos() lang := DW_LANG_Go - s := Ctxt.Textp + s := Ctxt.Textp[0] - dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, "go") + dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, "go", 0) newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT, int64(lang), 0) - newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart-lineo, 0) + newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, 0, 0) newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s.Value, s) // OS X linker requires compilation dir or absolute path in comp unit name to output debug info. compDir := getCompilationDir() @@ -1484,61 +1444,62 @@ func writelines() { // Write .debug_line Line Number Program Header (sec 6.2.4) // Fields marked with (*) must be changed for 64-bit dwarf - Thearch.Lput(0) // unit_length (*), will be filled in by flushunit. - Thearch.Wput(2) // dwarf version (appendix F) - Thearch.Lput(0) // header_length (*), filled in by flushunit. + unit_length_offset := ls.Size + Adduint32(Ctxt, ls, 0) // unit_length (*), filled in at end. + unitstart = ls.Size + Adduint16(Ctxt, ls, 2) // dwarf version (appendix F) + header_length_offset := ls.Size + Adduint32(Ctxt, ls, 0) // header_length (*), filled in at end. + headerstart = ls.Size // cpos == unitstart + 4 + 2 + 4 - Cput(1) // minimum_instruction_length - Cput(1) // default_is_stmt - Cput(LINE_BASE & 0xFF) // line_base - Cput(LINE_RANGE) // line_range - Cput(OPCODE_BASE) // opcode_base - Cput(0) // standard_opcode_lengths[1] - Cput(1) // standard_opcode_lengths[2] - Cput(1) // standard_opcode_lengths[3] - Cput(1) // standard_opcode_lengths[4] - Cput(1) // standard_opcode_lengths[5] - Cput(0) // standard_opcode_lengths[6] - Cput(0) // standard_opcode_lengths[7] - Cput(0) // standard_opcode_lengths[8] - Cput(1) // standard_opcode_lengths[9] - Cput(0) // include_directories (empty) - - files := make([]*LSym, Ctxt.Nhistfile) + Adduint8(Ctxt, ls, 1) // minimum_instruction_length + Adduint8(Ctxt, ls, 1) // default_is_stmt + Adduint8(Ctxt, ls, LINE_BASE&0xFF) // line_base + Adduint8(Ctxt, ls, LINE_RANGE) // line_range + Adduint8(Ctxt, ls, OPCODE_BASE) // opcode_base + Adduint8(Ctxt, ls, 0) // standard_opcode_lengths[1] + Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[2] + Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[3] + Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[4] + Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[5] + Adduint8(Ctxt, ls, 0) // standard_opcode_lengths[6] + Adduint8(Ctxt, ls, 0) // standard_opcode_lengths[7] + Adduint8(Ctxt, ls, 0) // standard_opcode_lengths[8] + Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[9] + Adduint8(Ctxt, ls, 0) // include_directories (empty) - for f := Ctxt.Filesyms; f != nil; f = f.Next { - files[f.Value-1] = f - } - - for i := 0; int32(i) < Ctxt.Nhistfile; i++ { - strnput(files[i].Name, len(files[i].Name)+4) + for _, f := range Ctxt.Filesyms { + Addstring(ls, f.Name) + Adduint8(Ctxt, ls, 0) + Adduint8(Ctxt, ls, 0) + Adduint8(Ctxt, ls, 0) } // 4 zeros: the string termination + 3 fields. - Cput(0) + Adduint8(Ctxt, ls, 0) // terminate file_names. - headerend = Cpos() + headerend = ls.Size - Cput(0) // start extended opcode - uleb128put(1 + int64(Thearch.Ptrsize)) - Cput(DW_LNE_set_address) + Adduint8(Ctxt, ls, 0) // start extended opcode + uleb128put(ls, 1+int64(SysArch.PtrSize)) + Adduint8(Ctxt, ls, DW_LNE_set_address) pc := s.Value line := 1 file := 1 if Linkmode == LinkExternal { - adddwarfrel(linesec, s, lineo, Thearch.Ptrsize, 0) + Addaddr(Ctxt, ls, s) } else { - addrput(pc) + addrput(ls, pc) } var pcfile Pciter var pcline Pciter - for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next { - s = Ctxt.Cursym + for _, Ctxt.Cursym = range Ctxt.Textp { + s := Ctxt.Cursym - dwfunc := newdie(dwinfo, DW_ABRV_FUNCTION, s.Name) + dwfunc := newdie(dwinfo, DW_ABRV_FUNCTION, s.Name, int(s.Version)) newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s.Value, s) epc = s.Value + s.Size epcs = s @@ -1547,14 +1508,14 @@ func writelines() { newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0) } - if s.Pcln == nil { + if s.FuncInfo == nil { continue } finddebugruntimepath(s) - pciterinit(Ctxt, &pcfile, &s.Pcln.Pcfile) - pciterinit(Ctxt, &pcline, &s.Pcln.Pcline) + pciterinit(Ctxt, &pcfile, &s.FuncInfo.Pcfile) + pciterinit(Ctxt, &pcline, &s.FuncInfo.Pcline) epc = pc for pcfile.done == 0 && pcline.done == 0 { if epc-s.Value >= int64(pcfile.nextpc) { @@ -1568,12 +1529,12 @@ func writelines() { } if int32(file) != pcfile.value { - Cput(DW_LNS_set_file) - uleb128put(int64(pcfile.value)) + Adduint8(Ctxt, ls, DW_LNS_set_file) + uleb128put(ls, int64(pcfile.value)) file = int(pcfile.value) } - putpclcdelta(s.Value+int64(pcline.pc)-pc, int64(pcline.value)-int64(line)) + putpclcdelta(ls, s.Value+int64(pcline.pc)-pc, int64(pcline.value)-int64(line)) pc = s.Value + int64(pcline.pc) line = int(pcline.value) @@ -1589,13 +1550,13 @@ func writelines() { dt, da int offs int64 ) - for _, a := range s.Autom { + for _, a := range s.FuncInfo.Autom { switch a.Name { case obj.A_AUTO: dt = DW_ABRV_AUTO offs = int64(a.Aoffset) if !haslinkregister() { - offs -= int64(Thearch.Ptrsize) + offs -= int64(SysArch.PtrSize) } case obj.A_PARAM: @@ -1610,7 +1571,7 @@ func writelines() { continue } var n string - if find(dwfunc, a.Asym.Name) != nil { + if findchild(dwfunc, a.Asym.Name) != nil { n = mkvarname(a.Asym.Name, da) } else { n = a.Asym.Name @@ -1621,7 +1582,7 @@ func writelines() { n = n[i+1:] } - dwvar := newdie(dwfunc, dt, n) + dwvar := newdie(dwfunc, dt, n, 0) newcfaoffsetattr(dwvar, int32(offs)) newrefattr(dwvar, DW_AT_type, defgotype(a.Gotype)) @@ -1642,22 +1603,29 @@ func writelines() { } } - flushunit(dwinfo, epc, epcs, unitstart, int32(headerend-unitstart-10)) - linesize = Cpos() - lineo + Adduint8(Ctxt, ls, 0) // start extended opcode + uleb128put(ls, 1) + Adduint8(Ctxt, ls, DW_LNE_end_sequence) + + newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, epc+1, epcs) + + setuint32(Ctxt, ls, unit_length_offset, uint32(ls.Size-unitstart)) + setuint32(Ctxt, ls, header_length_offset, uint32(headerend-headerstart)) + + return ls } /* * Emit .debug_frame */ const ( - CIERESERVE = 16 - DATAALIGNMENTFACTOR = -4 + dataAlignmentFactor = -4 ) // appendPCDeltaCFA appends per-PC CFA deltas to b and returns the final slice. func appendPCDeltaCFA(b []byte, deltapc, cfa int64) []byte { b = append(b, DW_CFA_def_cfa_offset_sf) - b = appendSleb128(b, cfa/DATAALIGNMENTFACTOR) + b = appendSleb128(b, cfa/dataAlignmentFactor) switch { case deltapc < 0x40: @@ -1675,60 +1643,68 @@ func appendPCDeltaCFA(b []byte, deltapc, cfa int64) []byte { return b } -func writeframes() { +func writeframes(prev *LSym) *LSym { if framesec == nil { - framesec = Linklookup(Ctxt, ".dwarfframe", 0) + framesec = Linklookup(Ctxt, ".debug_frame", 0) } + framesec.Type = obj.SDWARFSECT framesec.R = framesec.R[:0] - frameo = Cpos() + fs := framesec + prev.Next = fs // Emit the CIE, Section 6.4.1 - Thearch.Lput(CIERESERVE) // initial length, must be multiple of thearch.ptrsize - Thearch.Lput(0xffffffff) // cid. - Cput(3) // dwarf version (appendix F) - Cput(0) // augmentation "" - uleb128put(1) // code_alignment_factor - sleb128put(DATAALIGNMENTFACTOR) // guess - uleb128put(int64(Thearch.Dwarfreglr)) // return_address_register - - Cput(DW_CFA_def_cfa) - - uleb128put(int64(Thearch.Dwarfregsp)) // register SP (**ABI-dependent, defined in l.h) + cieReserve := uint32(16) if haslinkregister() { - uleb128put(int64(0)) // offset - } else { - uleb128put(int64(Thearch.Ptrsize)) // offset + cieReserve = 32 } + Adduint32(Ctxt, fs, cieReserve) // initial length, must be multiple of pointer size + Adduint32(Ctxt, fs, 0xffffffff) // cid. + Adduint8(Ctxt, fs, 3) // dwarf version (appendix F) + Adduint8(Ctxt, fs, 0) // augmentation "" + uleb128put(fs, 1) // code_alignment_factor + sleb128put(fs, dataAlignmentFactor) // all CFI offset calculations include multiplication with this factor + uleb128put(fs, int64(Thearch.Dwarfreglr)) // return_address_register - Cput(DW_CFA_offset_extended) - uleb128put(int64(Thearch.Dwarfreglr)) // return address + Adduint8(Ctxt, fs, DW_CFA_def_cfa) // Set the current frame address.. + uleb128put(fs, int64(Thearch.Dwarfregsp)) // ...to use the value in the platform's SP register (defined in l.go)... if haslinkregister() { - uleb128put(int64(0) / DATAALIGNMENTFACTOR) // at cfa - 0 + uleb128put(fs, int64(0)) // ...plus a 0 offset. + + Adduint8(Ctxt, fs, DW_CFA_same_value) // The platform's link register is unchanged during the prologue. + uleb128put(fs, int64(Thearch.Dwarfreglr)) + + Adduint8(Ctxt, fs, DW_CFA_val_offset) // The previous value... + uleb128put(fs, int64(Thearch.Dwarfregsp)) // ...of the platform's SP register... + uleb128put(fs, int64(0)) // ...is CFA+0. } else { - uleb128put(int64(-Thearch.Ptrsize) / DATAALIGNMENTFACTOR) // at cfa - x*4 + uleb128put(fs, int64(SysArch.PtrSize)) // ...plus the word size (because the call instruction implicitly adds one word to the frame). + + Adduint8(Ctxt, fs, DW_CFA_offset_extended) // The previous value... + uleb128put(fs, int64(Thearch.Dwarfreglr)) // ...of the return address... + uleb128put(fs, int64(-SysArch.PtrSize)/dataAlignmentFactor) // ...is saved at [CFA - (PtrSize/4)]. } // 4 is to exclude the length field. - pad := CIERESERVE + frameo + 4 - Cpos() + pad := int64(cieReserve) + 4 - fs.Size if pad < 0 { - Exitf("dwarf: CIERESERVE too small by %d bytes.", -pad) + Exitf("dwarf: cieReserve too small by %d bytes.", -pad) } - strnput("", int(pad)) + Addbytes(Ctxt, fs, zeros[:pad]) var deltaBuf []byte var pcsp Pciter - for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next { + for _, Ctxt.Cursym = range Ctxt.Textp { s := Ctxt.Cursym - if s.Pcln == nil { + if s.FuncInfo == nil { continue } // Emit a FDE, Section 6.4.1. // First build the section contents into a byte buffer. deltaBuf = deltaBuf[:0] - for pciterinit(Ctxt, &pcsp, &s.Pcln.Pcsp); pcsp.done == 0; pciternext(&pcsp) { + for pciterinit(Ctxt, &pcsp, &s.FuncInfo.Pcsp); pcsp.done == 0; pciternext(&pcsp) { nextpc := pcsp.nextpc // pciterinit goes up to the end of the function, @@ -1741,12 +1717,27 @@ func writeframes() { } if haslinkregister() { + // TODO(bryanpkc): This is imprecise. In general, the instruction + // that stores the return address to the stack frame is not the + // same one that allocates the frame. + if pcsp.value > 0 { + // The return address is preserved at (CFA-frame_size) + // after a stack frame has been allocated. + deltaBuf = append(deltaBuf, DW_CFA_offset_extended_sf) + deltaBuf = appendUleb128(deltaBuf, uint64(Thearch.Dwarfreglr)) + deltaBuf = appendSleb128(deltaBuf, -int64(pcsp.value)/dataAlignmentFactor) + } else { + // The return address is restored into the link register + // when a stack frame has been de-allocated. + deltaBuf = append(deltaBuf, DW_CFA_same_value) + deltaBuf = appendUleb128(deltaBuf, uint64(Thearch.Dwarfreglr)) + } deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(pcsp.value)) } else { - deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(Thearch.Ptrsize)+int64(pcsp.value)) + deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(SysArch.PtrSize)+int64(pcsp.value)) } } - pad := int(Rnd(int64(len(deltaBuf)), int64(Thearch.Ptrsize))) - len(deltaBuf) + pad := int(Rnd(int64(len(deltaBuf)), int64(SysArch.PtrSize))) - len(deltaBuf) deltaBuf = append(deltaBuf, zeros[:pad]...) // Emit the FDE header, Section 6.4.1. @@ -1754,21 +1745,17 @@ func writeframes() { // 4 bytes: Pointer to the CIE above, at offset 0 // ptrsize: initial location // ptrsize: address range - Thearch.Lput(uint32(4 + 2*Thearch.Ptrsize + len(deltaBuf))) // length (excludes itself) + Adduint32(Ctxt, fs, uint32(4+2*SysArch.PtrSize+len(deltaBuf))) // length (excludes itself) if Linkmode == LinkExternal { - adddwarfrel(framesec, framesym, frameo, 4, 0) // CIE offset - adddwarfrel(framesec, s, frameo, Thearch.Ptrsize, 0) // initial location + adddwarfref(Ctxt, fs, framesec, 4) } else { - Thearch.Lput(0) // CIE offset - addrput(s.Value) // initial location + Adduint32(Ctxt, fs, 0) // CIE offset } - addrput(s.Size) // address range - - Cwrite(deltaBuf) + Addaddr(Ctxt, fs, s) + addrput(fs, s.Size) // address range + Addbytes(Ctxt, fs, deltaBuf) } - - Cflush() - framesize = Cpos() - frameo + return fs } /* @@ -1778,12 +1765,14 @@ const ( COMPUNITHEADERSIZE = 4 + 2 + 4 + 1 ) -func writeinfo() { - fwdcount = 0 +func writeinfo(prev *LSym) *LSym { if infosec == nil { - infosec = Linklookup(Ctxt, ".dwarfinfo", 0) + infosec = Linklookup(Ctxt, ".debug_info", 0) } infosec.R = infosec.R[:0] + infosec.Type = obj.SDWARFINFO + infosec.Attr |= AttrReachable + prev.Next, prev = infosec, infosec if arangessec == nil { arangessec = Linklookup(Ctxt, ".dwarfaranges", 0) @@ -1791,32 +1780,30 @@ func writeinfo() { arangessec.R = arangessec.R[:0] for compunit := dwroot.child; compunit != nil; compunit = compunit.link { - unitstart := Cpos() + s := compunit.sym + prev.Next, prev = s, s // Write .debug_info Compilation Unit Header (sec 7.5.1) // Fields marked with (*) must be changed for 64-bit dwarf // This must match COMPUNITHEADERSIZE above. - Thearch.Lput(0) // unit_length (*), will be filled in later. - Thearch.Wput(2) // dwarf version (appendix F) + Adduint32(Ctxt, s, 0) // unit_length (*), will be filled in later. + Adduint16(Ctxt, s, 2) // dwarf version (appendix F) // debug_abbrev_offset (*) - if Linkmode == LinkExternal { - adddwarfrel(infosec, abbrevsym, infoo, 4, 0) - } else { - Thearch.Lput(0) - } + adddwarfref(Ctxt, s, abbrevsym, 4) - Cput(uint8(Thearch.Ptrsize)) // address_size + Adduint8(Ctxt, s, uint8(SysArch.PtrSize)) // address_size - putdie(compunit) + prev = putdie(prev, compunit) + cusize := s.Size - 4 // exclude the length field. + for child := s.Next; child != nil; child = child.Next { + cusize += child.Size + } - here := Cpos() - Cseek(unitstart) - Thearch.Lput(uint32(here - unitstart - 4)) // exclude the length field. - Cseek(here) + setuint32(Ctxt, s, 0, uint32(cusize)) + newattr(compunit, DW_AT_byte_size, DW_CLS_CONSTANT, cusize, 0) } - - Cflush() + return prev } /* @@ -1837,51 +1824,52 @@ func ispubtype(die *DWDie) bool { return die.abbrev >= DW_ABRV_NULLTYPE } -func writepub(ispub func(*DWDie) bool) int64 { - sectionstart := Cpos() +func writepub(sname string, ispub func(*DWDie) bool, prev *LSym) *LSym { + s := Linklookup(Ctxt, sname, 0) + s.Type = obj.SDWARFSECT + prev.Next = s for compunit := dwroot.child; compunit != nil; compunit = compunit.link { - unitend := infoo + infosize - unitstart := compunit.offs - COMPUNITHEADERSIZE - if compunit.link != nil { - unitend = compunit.link.offs - COMPUNITHEADERSIZE - } + sectionstart := s.Size + culength := uint32(getattr(compunit, DW_AT_byte_size).value) + 4 // Write .debug_pubnames/types Header (sec 6.1.1) - Thearch.Lput(0) // unit_length (*), will be filled in later. - Thearch.Wput(2) // dwarf version (appendix F) - Thearch.Lput(uint32(unitstart)) // debug_info_offset (of the Comp unit Header) - Thearch.Lput(uint32(unitend - unitstart)) // debug_info_length + Adduint32(Ctxt, s, 0) // unit_length (*), will be filled in later. + Adduint16(Ctxt, s, 2) // dwarf version (appendix F) + adddwarfref(Ctxt, s, compunit.sym, 4) // debug_info_offset (of the Comp unit Header) + Adduint32(Ctxt, s, culength) // debug_info_length for die := compunit.child; die != nil; die = die.link { if !ispub(die) { continue } - Thearch.Lput(uint32(die.offs - unitstart)) dwa := getattr(die, DW_AT_name) - strnput(dwa.data.(string), int(dwa.value+1)) + name := dwa.data.(string) + if die.sym == nil { + fmt.Println("Missing sym for ", name) + } + adddwarfref(Ctxt, s, die.sym, 4) + Addstring(s, name) } - Thearch.Lput(0) + Adduint32(Ctxt, s, 0) - here := Cpos() - Cseek(sectionstart) - Thearch.Lput(uint32(here - sectionstart - 4)) // exclude the length field. - Cseek(here) + setuint32(Ctxt, s, sectionstart, uint32(s.Size-sectionstart)-4) // exclude the length field. } - return sectionstart + return s } /* * emit .debug_aranges. _info must have been written before, * because we need die->offs of dw_globals. */ -func writearanges() int64 { - sectionstart := Cpos() +func writearanges(prev *LSym) *LSym { + s := Linklookup(Ctxt, ".debug_aranges", 0) + s.Type = obj.SDWARFSECT // The first tuple is aligned to a multiple of the size of a single tuple // (twice the size of an address) - headersize := int(Rnd(4+2+4+1+1, int64(Thearch.Ptrsize*2))) // don't count unit_length field itself + headersize := int(Rnd(4+2+4+1+1, int64(SysArch.PtrSize*2))) // don't count unit_length field itself for compunit := dwroot.child; compunit != nil; compunit = compunit.link { b := getattr(compunit, DW_AT_low_pc) @@ -1894,78 +1882,46 @@ func writearanges() int64 { } // Write .debug_aranges Header + entry (sec 6.1.2) - Thearch.Lput(uint32(headersize) + 4*uint32(Thearch.Ptrsize) - 4) // unit_length (*) - Thearch.Wput(2) // dwarf version (appendix F) + unitlength := uint32(headersize) + 4*uint32(SysArch.PtrSize) - 4 + Adduint32(Ctxt, s, unitlength) // unit_length (*) + Adduint16(Ctxt, s, 2) // dwarf version (appendix F) - value := compunit.offs - COMPUNITHEADERSIZE // debug_info_offset - if Linkmode == LinkExternal { - adddwarfrel(arangessec, infosym, sectionstart, 4, value) - } else { - Thearch.Lput(uint32(value)) - } + adddwarfref(Ctxt, s, compunit.sym, 4) - Cput(uint8(Thearch.Ptrsize)) // address_size - Cput(0) // segment_size - strnput("", headersize-(4+2+4+1+1)) // align to thearch.ptrsize - - if Linkmode == LinkExternal { - adddwarfrel(arangessec, b.data.(*LSym), sectionstart, Thearch.Ptrsize, b.value-(b.data.(*LSym)).Value) - } else { - addrput(b.value) + Adduint8(Ctxt, s, uint8(SysArch.PtrSize)) // address_size + Adduint8(Ctxt, s, 0) // segment_size + padding := headersize - (4 + 2 + 4 + 1 + 1) + for i := 0; i < padding; i++ { + Adduint8(Ctxt, s, 0) } - addrput(e.value - b.value) - addrput(0) - addrput(0) + Addaddrplus(Ctxt, s, b.data.(*LSym), b.value-(b.data.(*LSym)).Value) + addrput(s, e.value-b.value) + addrput(s, 0) + addrput(s, 0) } - - Cflush() - return sectionstart -} - -func writegdbscript() int64 { - sectionstart := Cpos() - - if gdbscript != "" { - Cput(1) // magic 1 byte? - strnput(gdbscript, len(gdbscript)+1) - Cflush() + if s.Size > 0 { + prev.Next = s + prev = s } - - return sectionstart + return prev } -func align(size int64) { - if HEADTYPE == obj.Hwindows { // Only Windows PE need section align. - strnput("", int(Rnd(size, PEFILEALIGN)-size)) - } -} +func writegdbscript(prev *LSym) *LSym { -func writedwarfreloc(s *LSym) int64 { - start := Cpos() - for ri := 0; ri < len(s.R); ri++ { - r := &s.R[ri] - i := -1 - if Iself { - i = Thearch.Elfreloc1(r, int64(r.Off)) - } else if HEADTYPE == obj.Hdarwin { - i = Thearch.Machoreloc1(r, int64(r.Off)) - } - if i < 0 { - Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name) - } + if gdbscript != "" { + s := Linklookup(Ctxt, ".debug_gdb_scripts", 0) + s.Type = obj.SDWARFSECT + prev.Next = s + prev = s + Adduint8(Ctxt, s, 1) // magic 1 byte? + Addstring(s, gdbscript) } - return start + return prev } -func addmachodwarfsect(prev *Section, name string) *Section { - sect := addsection(&Segdwarf, name, 04) - sect.Extnum = prev.Extnum + 1 - sym := Linklookup(Ctxt, name, 0) - sym.Sect = sect - return sect -} +var prototypedies map[string]*DWDie /* * This is the main entry point for generating dwarf. After emitting @@ -1976,58 +1932,52 @@ func addmachodwarfsect(prev *Section, name string) *Section { * passes. * */ -func Dwarfemitdebugsections() { +func dwarfgeneratedebugsyms() { if Debug['w'] != 0 { // disable dwarf return } + if Debug['s'] != 0 && HEADTYPE != obj.Hdarwin { + return + } + if HEADTYPE == obj.Hplan9 { + return + } if Linkmode == LinkExternal { if !Iself && HEADTYPE != obj.Hdarwin { return } - if HEADTYPE == obj.Hdarwin { - sect := Segdata.Sect - // find the last section. - for sect.Next != nil { - sect = sect.Next - } - sect = addmachodwarfsect(sect, ".debug_abbrev") - sect = addmachodwarfsect(sect, ".debug_line") - sect = addmachodwarfsect(sect, ".debug_frame") - sect = addmachodwarfsect(sect, ".debug_info") - - infosym = Linklookup(Ctxt, ".debug_info", 0) - infosym.Attr |= AttrHidden - - abbrevsym = Linklookup(Ctxt, ".debug_abbrev", 0) - abbrevsym.Attr |= AttrHidden - - linesym = Linklookup(Ctxt, ".debug_line", 0) - linesym.Attr |= AttrHidden + } - framesym = Linklookup(Ctxt, ".debug_frame", 0) - framesym.Attr |= AttrHidden - } + if Debug['v'] != 0 { + fmt.Fprintf(Bso, "%5.2f dwarf\n", obj.Cputime()) } // For diagnostic messages. newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, int64(len("dwtypes")), "dwtypes") - mkindex(&dwroot) - mkindex(&dwtypes) - mkindex(&dwglobals) - // Some types that must exist to define other ones. - newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>") + newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>", 0) - newdie(&dwtypes, DW_ABRV_NULLTYPE, "void") - newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer") + newdie(&dwtypes, DW_ABRV_NULLTYPE, "void", 0) + newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer", 0) - die := newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr") // needed for array size + die := newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr", 0) // needed for array size newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0) - newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, int64(Thearch.Ptrsize), 0) + newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, int64(SysArch.PtrSize), 0) newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, obj.KindUintptr, 0) + // Prototypes needed for type synthesis. + prototypedies = map[string]*DWDie{ + "type.runtime.stringStructDWARF": nil, + "type.runtime.slice": nil, + "type.runtime.hmap": nil, + "type.runtime.bmap": nil, + "type.runtime.sudog": nil, + "type.runtime.waitq": nil, + "type.runtime.hchan": nil, + } + // Needed by the prettyprinter code for interface inspection. defgotype(lookup_or_diag("type.runtime._type")) @@ -2036,12 +1986,10 @@ func Dwarfemitdebugsections() { genasmsym(defdwsymb) - writeabbrev() - align(abbrevsize) - writelines() - align(linesize) - writeframes() - align(framesize) + dwarfp = writeabbrev() + last := dwarfp + last = writelines(last) + last = writeframes(last) synthesizestringtypes(dwtypes.child) synthesizeslicetypes(dwtypes.child) @@ -2055,412 +2003,61 @@ func Dwarfemitdebugsections() { movetomodule(&dwtypes) movetomodule(&dwglobals) - infoo = Cpos() - writeinfo() - infoe := Cpos() - pubnameso = infoe - pubtypeso = infoe - arangeso = infoe - gdbscripto = infoe - - if fwdcount > 0 { - if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "%5.2f dwarf pass 2.\n", obj.Cputime()) - } - Cseek(infoo) - writeinfo() - if fwdcount > 0 { - Exitf("dwarf: unresolved references after first dwarf info pass") - } - - if infoe != Cpos() { - Exitf("dwarf: inconsistent second dwarf info pass") - } - } - - infosize = infoe - infoo - align(infosize) - - pubnameso = writepub(ispubname) - pubnamessize = Cpos() - pubnameso - align(pubnamessize) - - pubtypeso = writepub(ispubtype) - pubtypessize = Cpos() - pubtypeso - align(pubtypessize) - - arangeso = writearanges() - arangessize = Cpos() - arangeso - align(arangessize) - - gdbscripto = writegdbscript() - gdbscriptsize = Cpos() - gdbscripto - align(gdbscriptsize) + // Need to reorder symbols so SDWARFINFO is after all SDWARFSECT + // (but we need to generate dies before writepub) + writeinfo(last) + infosyms := last.Next - for Cpos()&7 != 0 { - Cput(0) - } - if HEADTYPE != obj.Hdarwin { - dwarfemitreloc() - } -} - -func dwarfemitreloc() { - if Debug['w'] != 0 { // disable dwarf - return - } - inforeloco = writedwarfreloc(infosec) - inforelocsize = Cpos() - inforeloco - align(inforelocsize) - - arangesreloco = writedwarfreloc(arangessec) - arangesrelocsize = Cpos() - arangesreloco - align(arangesrelocsize) - - linereloco = writedwarfreloc(linesec) - linerelocsize = Cpos() - linereloco - align(linerelocsize) - - framereloco = writedwarfreloc(framesec) - framerelocsize = Cpos() - framereloco - align(framerelocsize) + last = writepub(".debug_pubnames", ispubname, last) + last = writepub(".debug_pubtypes", ispubtype, last) + last = writearanges(last) + last = writegdbscript(last) + last.Next = infosyms } /* * Elf. */ -const ( - ElfStrDebugAbbrev = iota - ElfStrDebugAranges - ElfStrDebugFrame - ElfStrDebugInfo - ElfStrDebugLine - ElfStrDebugLoc - ElfStrDebugMacinfo - ElfStrDebugPubNames - ElfStrDebugPubTypes - ElfStrDebugRanges - ElfStrDebugStr - ElfStrGDBScripts - ElfStrRelDebugInfo - ElfStrRelDebugAranges - ElfStrRelDebugLine - ElfStrRelDebugFrame - NElfStrDbg -) - -var elfstrdbg [NElfStrDbg]int64 - func dwarfaddshstrings(shstrtab *LSym) { if Debug['w'] != 0 { // disable dwarf return } - elfstrdbg[ElfStrDebugAbbrev] = Addstring(shstrtab, ".debug_abbrev") - elfstrdbg[ElfStrDebugAranges] = Addstring(shstrtab, ".debug_aranges") - elfstrdbg[ElfStrDebugFrame] = Addstring(shstrtab, ".debug_frame") - elfstrdbg[ElfStrDebugInfo] = Addstring(shstrtab, ".debug_info") - elfstrdbg[ElfStrDebugLine] = Addstring(shstrtab, ".debug_line") - elfstrdbg[ElfStrDebugLoc] = Addstring(shstrtab, ".debug_loc") - elfstrdbg[ElfStrDebugMacinfo] = Addstring(shstrtab, ".debug_macinfo") - elfstrdbg[ElfStrDebugPubNames] = Addstring(shstrtab, ".debug_pubnames") - elfstrdbg[ElfStrDebugPubTypes] = Addstring(shstrtab, ".debug_pubtypes") - elfstrdbg[ElfStrDebugRanges] = Addstring(shstrtab, ".debug_ranges") - elfstrdbg[ElfStrDebugStr] = Addstring(shstrtab, ".debug_str") - elfstrdbg[ElfStrGDBScripts] = Addstring(shstrtab, ".debug_gdb_scripts") + Addstring(shstrtab, ".debug_abbrev") + Addstring(shstrtab, ".debug_aranges") + Addstring(shstrtab, ".debug_frame") + Addstring(shstrtab, ".debug_info") + Addstring(shstrtab, ".debug_line") + Addstring(shstrtab, ".debug_pubnames") + Addstring(shstrtab, ".debug_pubtypes") + Addstring(shstrtab, ".debug_gdb_scripts") if Linkmode == LinkExternal { - switch Thearch.Thechar { - case '0', '6', '7', '9', 'z': - elfstrdbg[ElfStrRelDebugInfo] = Addstring(shstrtab, ".rela.debug_info") - elfstrdbg[ElfStrRelDebugAranges] = Addstring(shstrtab, ".rela.debug_aranges") - elfstrdbg[ElfStrRelDebugLine] = Addstring(shstrtab, ".rela.debug_line") - elfstrdbg[ElfStrRelDebugFrame] = Addstring(shstrtab, ".rela.debug_frame") - default: - elfstrdbg[ElfStrRelDebugInfo] = Addstring(shstrtab, ".rel.debug_info") - elfstrdbg[ElfStrRelDebugAranges] = Addstring(shstrtab, ".rel.debug_aranges") - elfstrdbg[ElfStrRelDebugLine] = Addstring(shstrtab, ".rel.debug_line") - elfstrdbg[ElfStrRelDebugFrame] = Addstring(shstrtab, ".rel.debug_frame") - } - - infosym = Linklookup(Ctxt, ".debug_info", 0) - infosym.Attr |= AttrHidden - - abbrevsym = Linklookup(Ctxt, ".debug_abbrev", 0) - abbrevsym.Attr |= AttrHidden - - linesym = Linklookup(Ctxt, ".debug_line", 0) - linesym.Attr |= AttrHidden - - framesym = Linklookup(Ctxt, ".debug_frame", 0) - framesym.Attr |= AttrHidden + Addstring(shstrtab, elfRelType+".debug_info") + Addstring(shstrtab, elfRelType+".debug_aranges") + Addstring(shstrtab, elfRelType+".debug_line") + Addstring(shstrtab, elfRelType+".debug_frame") + Addstring(shstrtab, elfRelType+".debug_pubnames") + Addstring(shstrtab, elfRelType+".debug_pubtypes") } } -// Add section symbols for DWARF debug info. This is called before +// Add section symbols for DWARF debug info. This is called before // dwarfaddelfheaders. func dwarfaddelfsectionsyms() { - if infosym != nil { - infosympos = Cpos() - putelfsectionsym(infosym, 0) - } - - if abbrevsym != nil { - abbrevsympos = Cpos() - putelfsectionsym(abbrevsym, 0) - } - - if linesym != nil { - linesympos = Cpos() - putelfsectionsym(linesym, 0) - } - - if framesym != nil { - framesympos = Cpos() - putelfsectionsym(framesym, 0) - } -} - -func dwarfaddelfrelocheader(elfstr int, shdata *ElfShdr, off int64, size int64) { - sh := newElfShdr(elfstrdbg[elfstr]) - switch Thearch.Thechar { - case '0', '6', '7', '9', 'z': - sh.type_ = SHT_RELA - default: - sh.type_ = SHT_REL - } - - sh.entsize = uint64(Thearch.Ptrsize) * 2 - if sh.type_ == SHT_RELA { - sh.entsize += uint64(Thearch.Ptrsize) - } - sh.link = uint32(elfshname(".symtab").shnum) - sh.info = uint32(shdata.shnum) - sh.off = uint64(off) - sh.size = uint64(size) - sh.addralign = uint64(Thearch.Ptrsize) -} - -func dwarfaddelfheaders() { - if Debug['w'] != 0 { // disable dwarf - return - } - - sh := newElfShdr(elfstrdbg[ElfStrDebugAbbrev]) - sh.type_ = SHT_PROGBITS - sh.off = uint64(abbrevo) - sh.size = uint64(abbrevsize) - sh.addralign = 1 - if abbrevsympos > 0 { - putelfsymshndx(abbrevsympos, sh.shnum) - } - - sh = newElfShdr(elfstrdbg[ElfStrDebugLine]) - sh.type_ = SHT_PROGBITS - sh.off = uint64(lineo) - sh.size = uint64(linesize) - sh.addralign = 1 - if linesympos > 0 { - putelfsymshndx(linesympos, sh.shnum) - } - shline := sh - - sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]) - sh.type_ = SHT_PROGBITS - sh.off = uint64(frameo) - sh.size = uint64(framesize) - sh.addralign = 1 - if framesympos > 0 { - putelfsymshndx(framesympos, sh.shnum) - } - shframe := sh - - sh = newElfShdr(elfstrdbg[ElfStrDebugInfo]) - sh.type_ = SHT_PROGBITS - sh.off = uint64(infoo) - sh.size = uint64(infosize) - sh.addralign = 1 - if infosympos > 0 { - putelfsymshndx(infosympos, sh.shnum) - } - shinfo := sh - - if pubnamessize > 0 { - sh := newElfShdr(elfstrdbg[ElfStrDebugPubNames]) - sh.type_ = SHT_PROGBITS - sh.off = uint64(pubnameso) - sh.size = uint64(pubnamessize) - sh.addralign = 1 - } - - if pubtypessize > 0 { - sh := newElfShdr(elfstrdbg[ElfStrDebugPubTypes]) - sh.type_ = SHT_PROGBITS - sh.off = uint64(pubtypeso) - sh.size = uint64(pubtypessize) - sh.addralign = 1 - } - - var sharanges *ElfShdr - if arangessize != 0 { - sh := newElfShdr(elfstrdbg[ElfStrDebugAranges]) - sh.type_ = SHT_PROGBITS - sh.off = uint64(arangeso) - sh.size = uint64(arangessize) - sh.addralign = 1 - sharanges = sh - } - - if gdbscriptsize != 0 { - sh := newElfShdr(elfstrdbg[ElfStrGDBScripts]) - sh.type_ = SHT_PROGBITS - sh.off = uint64(gdbscripto) - sh.size = uint64(gdbscriptsize) - sh.addralign = 1 - } - - if inforelocsize != 0 { - dwarfaddelfrelocheader(ElfStrRelDebugInfo, shinfo, inforeloco, inforelocsize) - } - - if arangesrelocsize != 0 { - dwarfaddelfrelocheader(ElfStrRelDebugAranges, sharanges, arangesreloco, arangesrelocsize) - } - - if linerelocsize != 0 { - dwarfaddelfrelocheader(ElfStrRelDebugLine, shline, linereloco, linerelocsize) - } - - if framerelocsize != 0 { - dwarfaddelfrelocheader(ElfStrRelDebugFrame, shframe, framereloco, framerelocsize) - } -} - -/* - * Macho - */ -func dwarfaddmachoheaders(ms *MachoSeg) { if Debug['w'] != 0 { // disable dwarf return } - - // Zero vsize segments won't be loaded in memory, even so they - // have to be page aligned in the file. - fakestart := Rnd(int64(Segdwarf.Fileoff), 0x1000) - addr := Segdata.Vaddr + Segdata.Length - - nsect := 4 - if pubnamessize > 0 { - nsect++ - } - if pubtypessize > 0 { - nsect++ - } - if arangessize > 0 { - nsect++ - } - if gdbscriptsize > 0 { - nsect++ - } - if Linkmode != LinkExternal { - ms = newMachoSeg("__DWARF", nsect) - ms.fileoffset = uint64(fakestart) - ms.filesize = Segdwarf.Filelen - ms.vaddr = addr - } - - msect := newMachoSect(ms, "__debug_abbrev", "__DWARF") - msect.off = uint32(abbrevo) - msect.size = uint64(abbrevsize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 - if abbrevsym != nil { - abbrevsym.Value = int64(msect.addr) - } - - msect = newMachoSect(ms, "__debug_line", "__DWARF") - msect.off = uint32(lineo) - msect.size = uint64(linesize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 - if linesym != nil { - linesym.Value = int64(msect.addr) - } - if linerelocsize > 0 { - msect.nreloc = uint32(len(linesec.R)) - msect.reloc = uint32(linereloco) - } - - msect = newMachoSect(ms, "__debug_frame", "__DWARF") - msect.off = uint32(frameo) - msect.size = uint64(framesize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 - if framesym != nil { - framesym.Value = int64(msect.addr) - } - if framerelocsize > 0 { - msect.nreloc = uint32(len(framesec.R)) - msect.reloc = uint32(framereloco) - } - - msect = newMachoSect(ms, "__debug_info", "__DWARF") - msect.off = uint32(infoo) - msect.size = uint64(infosize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 - if infosym != nil { - infosym.Value = int64(msect.addr) - } - if inforelocsize > 0 { - msect.nreloc = uint32(len(infosec.R)) - msect.reloc = uint32(inforeloco) - } - - if pubnamessize > 0 { - msect := newMachoSect(ms, "__debug_pubnames", "__DWARF") - msect.off = uint32(pubnameso) - msect.size = uint64(pubnamessize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 - } - - if pubtypessize > 0 { - msect := newMachoSect(ms, "__debug_pubtypes", "__DWARF") - msect.off = uint32(pubtypeso) - msect.size = uint64(pubtypessize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 - } - - if arangessize > 0 { - msect := newMachoSect(ms, "__debug_aranges", "__DWARF") - msect.off = uint32(arangeso) - msect.size = uint64(arangessize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 - if arangesrelocsize > 0 { - msect.nreloc = uint32(len(arangessec.R)) - msect.reloc = uint32(arangesreloco) - } - } - - // TODO(lvd) fix gdb/python to load MachO (16 char section name limit) - if gdbscriptsize > 0 { - msect := newMachoSect(ms, "__debug_gdb_scripts", "__DWARF") - msect.off = uint32(gdbscripto) - msect.size = uint64(gdbscriptsize) - msect.addr = addr - addr += msect.size - msect.flag = 0x02000000 + return } + sym := Linklookup(Ctxt, ".debug_info", 0) + putelfsectionsym(sym, sym.Sect.Elfsect.shnum) + sym = Linklookup(Ctxt, ".debug_abbrev", 0) + putelfsectionsym(sym, sym.Sect.Elfsect.shnum) + sym = Linklookup(Ctxt, ".debug_line", 0) + putelfsectionsym(sym, sym.Sect.Elfsect.shnum) + sym = Linklookup(Ctxt, ".debug_frame", 0) + putelfsectionsym(sym, sym.Sect.Elfsect.shnum) } /* @@ -2470,13 +2067,12 @@ func dwarfaddpeheaders() { if Debug['w'] != 0 { // disable dwarf return } - - newPEDWARFSection(".debug_abbrev", abbrevsize) - newPEDWARFSection(".debug_line", linesize) - newPEDWARFSection(".debug_frame", framesize) - newPEDWARFSection(".debug_info", infosize) - newPEDWARFSection(".debug_pubnames", pubnamessize) - newPEDWARFSection(".debug_pubtypes", pubtypessize) - newPEDWARFSection(".debug_aranges", arangessize) - newPEDWARFSection(".debug_gdb_scripts", gdbscriptsize) + for sect := Segdwarf.Sect; sect != nil; sect = sect.Next { + h := newPEDWARFSection(sect.Name, int64(sect.Length)) + fileoff := sect.Vaddr - Segdwarf.Vaddr + Segdwarf.Fileoff + if uint64(h.PointerToRawData) != fileoff { + Diag("%s.PointerToRawData = %#x, want %#x", sect.Name, h.PointerToRawData, fileoff) + errorexit() + } + } } diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index ffb7c4bdde..15b8d7af93 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -6,6 +6,7 @@ package ld import ( "cmd/internal/obj" + "cmd/internal/sys" "crypto/sha1" "encoding/binary" "encoding/hex" @@ -866,25 +867,23 @@ var buildinfo []byte func Elfinit() { Iself = true - switch Thearch.Thechar { - case '0', '6', '7', '9', 'z': + if SysArch.InFamily(sys.AMD64, sys.ARM64, sys.MIPS64, sys.PPC64, sys.S390X) { elfRelType = ".rela" - default: + } else { elfRelType = ".rel" } - switch Thearch.Thechar { + switch SysArch.Family { // 64-bit architectures - case '9', 'z': + case sys.PPC64, sys.S390X: if Ctxt.Arch.ByteOrder == binary.BigEndian { ehdr.flags = 1 /* Version 1 ABI */ } else { ehdr.flags = 2 /* Version 2 ABI */ } fallthrough - - case '0', '6', '7': - if Thearch.Thechar == '0' { + case sys.AMD64, sys.ARM64, sys.MIPS64: + if SysArch.Family == sys.MIPS64 { ehdr.flags = 0x20000000 /* MIPS 3 */ } elf64 = true @@ -897,7 +896,7 @@ func Elfinit() { // we use EABI on both linux/arm and freebsd/arm. // 32-bit architectures - case '5': + case sys.ARM: // we use EABI on both linux/arm and freebsd/arm. if HEADTYPE == obj.Hlinux || HEADTYPE == obj.Hfreebsd { // We set a value here that makes no indication of which @@ -911,7 +910,6 @@ func Elfinit() { ehdr.flags = 0x5000002 // has entry point, Version5 EABI } fallthrough - default: ehdr.phoff = ELF32HDRSIZE /* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */ @@ -1432,7 +1430,7 @@ func elfdynhash() { } // s390x (ELF64) hash table entries are 8 bytes - if Thearch.Thechar == 'z' { + if SysArch.Family == sys.S390X { Adduint64(Ctxt, s, uint64(nbucket)) Adduint64(Ctxt, s, uint64(nsym)) for i := 0; i < nbucket; i++ { @@ -1622,6 +1620,9 @@ func elfshbits(sect *Section) *ElfShdr { sh.flags |= SHF_TLS sh.type_ = SHT_NOBITS } + if strings.HasPrefix(sect.Name, ".debug") { + sh.flags = 0 + } if Linkmode != LinkExternal { sh.addr = sect.Vaddr @@ -1657,19 +1658,19 @@ func elfshreloc(sect *Section) *ElfShdr { sh := elfshname(elfRelType + sect.Name) sh.type_ = uint32(typ) - sh.entsize = uint64(Thearch.Regsize) * 2 + sh.entsize = uint64(SysArch.RegSize) * 2 if typ == SHT_RELA { - sh.entsize += uint64(Thearch.Regsize) + sh.entsize += uint64(SysArch.RegSize) } sh.link = uint32(elfshname(".symtab").shnum) sh.info = uint32(sect.Elfsect.shnum) sh.off = sect.Reloff sh.size = sect.Rellen - sh.addralign = uint64(Thearch.Regsize) + sh.addralign = uint64(SysArch.RegSize) return sh } -func elfrelocsect(sect *Section, first *LSym) { +func elfrelocsect(sect *Section, syms []*LSym) { // If main section is SHT_NOBITS, nothing to relocate. // Also nothing to relocate in .shstrtab. if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { @@ -1680,20 +1681,18 @@ func elfrelocsect(sect *Section, first *LSym) { } sect.Reloff = uint64(Cpos()) - var sym *LSym - for sym = first; sym != nil; sym = sym.Next { - if !sym.Attr.Reachable() { + for i, s := range syms { + if !s.Attr.Reachable() { continue } - if uint64(sym.Value) >= sect.Vaddr { + if uint64(s.Value) >= sect.Vaddr { + syms = syms[i:] break } } eaddr := int32(sect.Vaddr + sect.Length) - var r *Reloc - var ri int - for ; sym != nil; sym = sym.Next { + for _, sym := range syms { if !sym.Attr.Reachable() { continue } @@ -1702,8 +1701,8 @@ func elfrelocsect(sect *Section, first *LSym) { } Ctxt.Cursym = sym - for ri = 0; ri < len(sym.R); ri++ { - r = &sym.R[ri] + for ri := 0; ri < len(sym.R); ri++ { + r := &sym.R[ri] if r.Done != 0 { continue } @@ -1711,7 +1710,6 @@ func elfrelocsect(sect *Section, first *LSym) { Diag("missing xsym in relocation") continue } - if r.Xsym.ElfsymForReloc() == 0 { Diag("reloc %d to non-elf symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type) } @@ -1739,6 +1737,9 @@ func Elfemitreloc() { for sect := Segdata.Sect; sect != nil; sect = sect.Next { elfrelocsect(sect, datap) } + for sect := Segdwarf.Sect; sect != nil; sect = sect.Next { + elfrelocsect(sect, list2slice(dwarfp)) + } } func addgonote(sectionName string, tag uint32, desc []byte) { @@ -1866,7 +1867,7 @@ func doelf() { Addstring(shstrtab, ".interp") Addstring(shstrtab, ".hash") Addstring(shstrtab, ".got") - if Thearch.Thechar == '9' { + if SysArch.Family == sys.PPC64 { Addstring(shstrtab, ".glink") } Addstring(shstrtab, ".got.plt") @@ -1885,10 +1886,9 @@ func doelf() { s.Type = obj.SELFROSECT s.Attr |= AttrReachable - switch Thearch.Thechar { - case '0', '6', '7', '9', 'z': + if elf64 { s.Size += ELF64SYMSIZE - default: + } else { s.Size += ELF32SYMSIZE } @@ -1914,7 +1914,7 @@ func doelf() { s.Type = obj.SELFGOT // writable /* ppc64 glink resolver */ - if Thearch.Thechar == '9' { + if SysArch.Family == sys.PPC64 { s := Linklookup(Ctxt, ".glink", 0) s.Attr |= AttrReachable s.Type = obj.SELFRXSECT @@ -1933,7 +1933,7 @@ func doelf() { s = Linklookup(Ctxt, ".plt", 0) s.Attr |= AttrReachable - if Thearch.Thechar == '9' { + if SysArch.Family == sys.PPC64 { // In the ppc64 ABI, .plt is a data section // written by the dynamic linker. s.Type = obj.SELFSECT @@ -1967,10 +1967,9 @@ func doelf() { elfwritedynentsym(s, DT_HASH, Linklookup(Ctxt, ".hash", 0)) elfwritedynentsym(s, DT_SYMTAB, Linklookup(Ctxt, ".dynsym", 0)) - switch Thearch.Thechar { - case '0', '6', '7', '9', 'z': + if elf64 { Elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE) - default: + } else { Elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE) } elfwritedynentsym(s, DT_STRTAB, Linklookup(Ctxt, ".dynstr", 0)) @@ -1989,15 +1988,15 @@ func doelf() { Elfwritedynent(s, DT_RUNPATH, uint64(Addstring(dynstr, rpath.val))) } - if Thearch.Thechar == '9' { + if SysArch.Family == sys.PPC64 { elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".plt", 0)) - } else if Thearch.Thechar == 'z' { + } else if SysArch.Family == sys.S390X { elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".got", 0)) } else { elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".got.plt", 0)) } - if Thearch.Thechar == '9' { + if SysArch.Family == sys.PPC64 { Elfwritedynent(s, DT_PPC64_OPT, 0) } @@ -2024,7 +2023,7 @@ func doelf() { h.Write(l.hash) } addgonote(".note.go.abihash", ELF_NOTE_GOABIHASH_TAG, h.Sum([]byte{})) - addgonote(".note.go.pkg-list", ELF_NOTE_GOPKGLIST_TAG, []byte(pkglistfornote)) + addgonote(".note.go.pkg-list", ELF_NOTE_GOPKGLIST_TAG, pkglistfornote) var deplist []string for _, shlib := range Ctxt.Shlibs { deplist = append(deplist, filepath.Base(shlib.Path)) @@ -2069,26 +2068,29 @@ func Asmbelfsetup() { for sect := Segdata.Sect; sect != nil; sect = sect.Next { elfshalloc(sect) } + for sect := Segdwarf.Sect; sect != nil; sect = sect.Next { + elfshalloc(sect) + } } func Asmbelf(symo int64) { eh := getElfEhdr() - switch Thearch.Thechar { + switch SysArch.Family { default: - Exitf("unknown architecture in asmbelf: %v", Thearch.Thechar) - case '0': + Exitf("unknown architecture in asmbelf: %v", SysArch.Family) + case sys.MIPS64: eh.machine = EM_MIPS - case '5': + case sys.ARM: eh.machine = EM_ARM - case '6': + case sys.AMD64: eh.machine = EM_X86_64 - case '7': + case sys.ARM64: eh.machine = EM_AARCH64 - case '8': + case sys.I386: eh.machine = EM_386 - case '9': + case sys.PPC64: eh.machine = EM_PPC64 - case 'z': + case sys.S390X: eh.machine = EM_S390 } @@ -2244,7 +2246,7 @@ func Asmbelf(symo int64) { } else { sh.entsize = ELF32SYMSIZE } - sh.addralign = uint64(Thearch.Regsize) + sh.addralign = uint64(SysArch.RegSize) sh.link = uint32(elfshname(".dynstr").shnum) // sh->info = index of first non-local symbol (number of local symbols) @@ -2268,7 +2270,7 @@ func Asmbelf(symo int64) { sh = elfshname(".gnu.version_r") sh.type_ = SHT_GNU_VERNEED sh.flags = SHF_ALLOC - sh.addralign = uint64(Thearch.Regsize) + sh.addralign = uint64(SysArch.RegSize) sh.info = uint32(elfverneed) sh.link = uint32(elfshname(".dynstr").shnum) shsym(sh, Linklookup(Ctxt, ".gnu.version_r", 0)) @@ -2279,7 +2281,7 @@ func Asmbelf(symo int64) { sh.type_ = SHT_RELA sh.flags = SHF_ALLOC sh.entsize = ELF64RELASIZE - sh.addralign = uint64(Thearch.Regsize) + sh.addralign = uint64(SysArch.RegSize) sh.link = uint32(elfshname(".dynsym").shnum) sh.info = uint32(elfshname(".plt").shnum) shsym(sh, Linklookup(Ctxt, ".rela.plt", 0)) @@ -2343,15 +2345,15 @@ func Asmbelf(symo int64) { sh := elfshname(".got") sh.type_ = SHT_PROGBITS sh.flags = SHF_ALLOC + SHF_WRITE - sh.entsize = uint64(Thearch.Regsize) - sh.addralign = uint64(Thearch.Regsize) + sh.entsize = uint64(SysArch.RegSize) + sh.addralign = uint64(SysArch.RegSize) shsym(sh, Linklookup(Ctxt, ".got", 0)) sh = elfshname(".got.plt") sh.type_ = SHT_PROGBITS sh.flags = SHF_ALLOC + SHF_WRITE - sh.entsize = uint64(Thearch.Regsize) - sh.addralign = uint64(Thearch.Regsize) + sh.entsize = uint64(SysArch.RegSize) + sh.addralign = uint64(SysArch.RegSize) shsym(sh, Linklookup(Ctxt, ".got.plt", 0)) } @@ -2359,7 +2361,7 @@ func Asmbelf(symo int64) { sh.type_ = SHT_HASH sh.flags = SHF_ALLOC sh.entsize = 4 - sh.addralign = uint64(Thearch.Regsize) + sh.addralign = uint64(SysArch.RegSize) sh.link = uint32(elfshname(".dynsym").shnum) shsym(sh, Linklookup(Ctxt, ".hash", 0)) @@ -2368,8 +2370,8 @@ func Asmbelf(symo int64) { sh.type_ = SHT_DYNAMIC sh.flags = SHF_ALLOC + SHF_WRITE - sh.entsize = 2 * uint64(Thearch.Regsize) - sh.addralign = uint64(Thearch.Regsize) + sh.entsize = 2 * uint64(SysArch.RegSize) + sh.addralign = uint64(SysArch.RegSize) sh.link = uint32(elfshname(".dynstr").shnum) shsym(sh, Linklookup(Ctxt, ".dynamic", 0)) ph := newElfPhdr() @@ -2395,7 +2397,7 @@ func Asmbelf(symo int64) { ph.type_ = PT_TLS ph.flags = PF_R ph.memsz = tlssize - ph.align = uint64(Thearch.Regsize) + ph.align = uint64(SysArch.RegSize) } } } @@ -2404,12 +2406,12 @@ func Asmbelf(symo int64) { ph := newElfPhdr() ph.type_ = PT_GNU_STACK ph.flags = PF_W + PF_R - ph.align = uint64(Thearch.Regsize) + ph.align = uint64(SysArch.RegSize) ph = newElfPhdr() ph.type_ = PT_PAX_FLAGS ph.flags = 0x2a00 // mprotect, randexec, emutramp disabled - ph.align = uint64(Thearch.Regsize) + ph.align = uint64(SysArch.RegSize) } elfobj: @@ -2434,6 +2436,9 @@ elfobj: for sect := Segdata.Sect; sect != nil; sect = sect.Next { elfshbits(sect) } + for sect := Segdwarf.Sect; sect != nil; sect = sect.Next { + elfshbits(sect) + } if Linkmode == LinkExternal { for sect := Segtext.Sect; sect != nil; sect = sect.Next { @@ -2445,7 +2450,14 @@ elfobj: for sect := Segdata.Sect; sect != nil; sect = sect.Next { elfshreloc(sect) } - + for s := dwarfp; s != nil; s = s.Next { + if len(s.R) > 0 || s.Type == obj.SDWARFINFO { + elfshreloc(s.Sect) + } + if s.Type == obj.SDWARFINFO { + break + } + } // add a .note.GNU-stack section to mark the stack as non-executable sh := elfshname(".note.GNU-stack") @@ -2459,8 +2471,8 @@ elfobj: sh.type_ = SHT_SYMTAB sh.off = uint64(symo) sh.size = uint64(Symsize) - sh.addralign = uint64(Thearch.Regsize) - sh.entsize = 8 + 2*uint64(Thearch.Regsize) + sh.addralign = uint64(SysArch.RegSize) + sh.entsize = 8 + 2*uint64(SysArch.RegSize) sh.link = uint32(elfshname(".strtab").shnum) sh.info = uint32(elfglobalsymndx) @@ -2469,8 +2481,6 @@ elfobj: sh.off = uint64(symo) + uint64(Symsize) sh.size = uint64(len(Elfstrdat)) sh.addralign = 1 - - dwarfaddelfheaders() } /* Main header */ @@ -2585,7 +2595,7 @@ func Elfadddynsym(ctxt *Link, s *LSym) { /* size of object */ Adduint64(ctxt, d, uint64(s.Size)) - if Thearch.Thechar == '6' && !s.Attr.CgoExportDynamic() && s.Dynimplib != "" && !seenlib[s.Dynimplib] { + if SysArch.Family == sys.AMD64 && !s.Attr.CgoExportDynamic() && s.Dynimplib != "" && !seenlib[s.Dynimplib] { Elfwritedynent(Linklookup(ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(Linklookup(ctxt, ".dynstr", 0), s.Dynimplib))) } } else { @@ -2613,9 +2623,9 @@ func Elfadddynsym(ctxt *Link, s *LSym) { t := STB_GLOBAL << 4 // TODO(mwhudson): presumably the behaviour should actually be the same on both arm and 386. - if Thearch.Thechar == '8' && s.Attr.CgoExport() && s.Type&obj.SMASK == obj.STEXT { + if SysArch.Family == sys.I386 && s.Attr.CgoExport() && s.Type&obj.SMASK == obj.STEXT { t |= STT_FUNC - } else if Thearch.Thechar == '5' && s.Attr.CgoExportDynamic() && s.Type&obj.SMASK == obj.STEXT { + } else if SysArch.Family == sys.ARM && s.Attr.CgoExportDynamic() && s.Type&obj.SMASK == obj.STEXT { t |= STT_FUNC } else { t |= STT_OBJECT diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go index 027e05d845..425c75571f 100644 --- a/src/cmd/link/internal/ld/go.go +++ b/src/cmd/link/internal/ld/go.go @@ -8,8 +8,10 @@ package ld import ( "bytes" + "cmd/internal/bio" "cmd/internal/obj" "fmt" + "io" "os" "strings" ) @@ -26,7 +28,7 @@ func expandpkg(t0 string, pkg string) string { // once the dust settles, try to move some code to // libmach, so that other linkers and ar can share. -func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int) { +func ldpkg(f *bio.Reader, pkg string, length int64, filename string, whence int) { var p0, p1 int if Debug['g'] != 0 { @@ -48,7 +50,7 @@ func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int) } bdata := make([]byte, length) - if int64(obj.Bread(f, bdata)) != length { + if _, err := io.ReadFull(f, bdata); err != nil { fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename) if Debug['u'] != 0 { errorexit() @@ -418,35 +420,7 @@ type Pkg struct { impby []*Pkg } -var ( - // pkgmap records the imported-by relationship between packages. - // Entries are keyed by package path (e.g., "runtime" or "net/url"). - pkgmap = map[string]*Pkg{} - - pkgall []*Pkg -) - -func lookupPkg(path string) *Pkg { - if p, ok := pkgmap[path]; ok { - return p - } - p := &Pkg{path: path} - pkgmap[path] = p - pkgall = append(pkgall, p) - return p -} - -// imported records that package pkg imports package imp. -func imported(pkg, imp string) { - // everyone imports runtime, even runtime. - if imp == "runtime" { - return - } - - p := lookupPkg(pkg) - i := lookupPkg(imp) - i.impby = append(i.impby, p) -} +var pkgall []*Pkg func (p *Pkg) cycle() *Pkg { if p.checked { diff --git a/src/cmd/link/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go index 0255331ac6..af60a5c85b 100644 --- a/src/cmd/link/internal/ld/ldelf.go +++ b/src/cmd/link/internal/ld/ldelf.go @@ -2,7 +2,9 @@ package ld import ( "bytes" + "cmd/internal/bio" "cmd/internal/obj" + "cmd/internal/sys" "encoding/binary" "fmt" "io" @@ -266,7 +268,7 @@ type ElfSect struct { } type ElfObj struct { - f *obj.Biobuf + f *bio.Reader base int64 // offset in f where ELF begins length int64 // length of ELF is64 int @@ -403,7 +405,7 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) { ehdr.flags = 0x5000202 } if data[0] != 'A' { - fmt.Fprintf(&Bso, ".ARM.attributes has unexpected format %c\n", data[0]) + fmt.Fprintf(Bso, ".ARM.attributes has unexpected format %c\n", data[0]) return } data = data[1:] @@ -414,7 +416,7 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) { nulIndex := bytes.IndexByte(sectiondata, 0) if nulIndex < 0 { - fmt.Fprintf(&Bso, "corrupt .ARM.attributes (section name not NUL-terminated)\n") + fmt.Fprintf(Bso, "corrupt .ARM.attributes (section name not NUL-terminated)\n") return } name := string(sectiondata[:nulIndex]) @@ -438,20 +440,20 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) { } } if attrList.err != nil { - fmt.Fprintf(&Bso, "could not parse .ARM.attributes\n") + fmt.Fprintf(Bso, "could not parse .ARM.attributes\n") } } } } } -func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) { +func ldelf(f *bio.Reader, pkg string, length int64, pn string) { if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "%5.2f ldelf %s\n", obj.Cputime(), pn) + fmt.Fprintf(Bso, "%5.2f ldelf %s\n", obj.Cputime(), pn) } Ctxt.IncVersion() - base := int32(obj.Boffset(f)) + base := f.Offset() var add uint64 var e binary.ByteOrder @@ -474,7 +476,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) { var sect *ElfSect var sym ElfSym var symbols []*LSym - if obj.Bread(f, hdrbuf[:]) != len(hdrbuf) { + if _, err := io.ReadFull(f, hdrbuf[:]); err != nil { goto bad } hdr = new(ElfHdrBytes) @@ -498,7 +500,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) { elfobj.e = e elfobj.f = f - elfobj.base = int64(base) + elfobj.base = base elfobj.length = length elfobj.name = pn @@ -546,47 +548,48 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) { return } - switch Thearch.Thechar { + switch SysArch.Family { default: - Diag("%s: elf %s unimplemented", pn, Thestring) + Diag("%s: elf %s unimplemented", pn, SysArch.Name) return - case '0': + case sys.MIPS64: if elfobj.machine != ElfMachMips || hdr.Ident[4] != ElfClass64 { Diag("%s: elf object but not mips64", pn) return } - case '5': + case sys.ARM: if e != binary.LittleEndian || elfobj.machine != ElfMachArm || hdr.Ident[4] != ElfClass32 { Diag("%s: elf object but not arm", pn) return } - case '6': + case sys.AMD64: if e != binary.LittleEndian || elfobj.machine != ElfMachAmd64 || hdr.Ident[4] != ElfClass64 { Diag("%s: elf object but not amd64", pn) return } - case '7': + case sys.ARM64: if e != binary.LittleEndian || elfobj.machine != ElfMachArm64 || hdr.Ident[4] != ElfClass64 { Diag("%s: elf object but not arm64", pn) return } - case '8': + case sys.I386: if e != binary.LittleEndian || elfobj.machine != ElfMach386 || hdr.Ident[4] != ElfClass32 { Diag("%s: elf object but not 386", pn) return } - case '9': + case sys.PPC64: if elfobj.machine != ElfMachPower64 || hdr.Ident[4] != ElfClass64 { Diag("%s: elf object but not ppc64", pn) return } - case 'z': + + case sys.S390X: if elfobj.machine != ElfMachS390 || hdr.Ident[4] != ElfClass64 { Diag("%s: elf object but not s390x", pn) return @@ -598,7 +601,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) { elfobj.nsect = uint(elfobj.shnum) for i := 0; uint(i) < elfobj.nsect; i++ { - if obj.Bseek(f, int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 { + if f.Seek(int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 { goto bad } sect = &elfobj.sect[i] @@ -609,7 +612,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) { goto bad } - sect.nameoff = uint32(e.Uint32(b.Name[:])) + sect.nameoff = e.Uint32(b.Name[:]) sect.type_ = e.Uint32(b.Type[:]) sect.flags = e.Uint64(b.Flags[:]) sect.addr = e.Uint64(b.Addr[:]) @@ -626,7 +629,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) { goto bad } - sect.nameoff = uint32(e.Uint32(b.Name[:])) + sect.nameoff = e.Uint32(b.Name[:]) sect.type_ = e.Uint32(b.Type[:]) sect.flags = uint64(e.Uint32(b.Flags[:])) sect.addr = uint64(e.Uint32(b.Addr[:])) @@ -771,7 +774,7 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) { if sym.sym == nil { continue } - sect = &elfobj.sect[sym.shndx:][0] + sect = &elfobj.sect[sym.shndx] if sect.sym == nil { if strings.HasPrefix(sym.name, ".Linfo_string") { // clang does this continue @@ -839,19 +842,13 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) { log.Fatalf("symbol %s listed multiple times", s.Name) } s.Attr |= AttrOnList - if Ctxt.Etextp != nil { - Ctxt.Etextp.Next = s - } else { - Ctxt.Textp = s - } - Ctxt.Etextp = s + Ctxt.Textp = append(Ctxt.Textp, s) for s = s.Sub; s != nil; s = s.Sub { if s.Attr.OnList() { log.Fatalf("symbol %s listed multiple times", s.Name) } s.Attr |= AttrOnList - Ctxt.Etextp.Next = s - Ctxt.Etextp = s + Ctxt.Textp = append(Ctxt.Textp, s) } } } @@ -925,7 +922,8 @@ func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) { rp.Sym = sym.sym } - rp.Type = int32(reltype(pn, int(uint32(info)), &rp.Siz)) + rp.Type = 256 + int32(info) + rp.Siz = relSize(pn, uint32(info)) if rela != 0 { rp.Add = int64(add) } else { @@ -982,9 +980,11 @@ func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) { } sect.base = make([]byte, sect.size) - err = fmt.Errorf("short read") - if obj.Bseek(elfobj.f, int64(uint64(elfobj.base)+sect.off), 0) < 0 || obj.Bread(elfobj.f, sect.base) != len(sect.base) { - return err + if elfobj.f.Seek(int64(uint64(elfobj.base)+sect.off), 0) < 0 { + return fmt.Errorf("short read: seek not successful") + } + if _, err := io.ReadFull(elfobj.f, sect.base); err != nil { + return fmt.Errorf("short read: %v", err) } return nil @@ -1056,7 +1056,7 @@ func readelfsym(elfobj *ElfObj, i int, sym *ElfSym, needSym int) (err error) { } case ElfSymBindLocal: - if Thearch.Thechar == '5' && (strings.HasPrefix(sym.name, "$a") || strings.HasPrefix(sym.name, "$d")) { + if SysArch.Family == sys.ARM && (strings.HasPrefix(sym.name, "$a") || strings.HasPrefix(sym.name, "$d")) { // binutils for arm generate these mapping // symbols, ignore these break @@ -1126,79 +1126,89 @@ func (x rbyoff) Less(i, j int) bool { return false } -func reltype(pn string, elftype int, siz *uint8) int { - switch uint32(Thearch.Thechar) | uint32(elftype)<<24 { +func relSize(pn string, elftype uint32) uint8 { + // TODO(mdempsky): Replace this with a struct-valued switch statement + // once golang.org/issue/15164 is fixed or found to not impair cmd/link + // performance. + + const ( + AMD64 = uint32(sys.AMD64) + ARM = uint32(sys.ARM) + I386 = uint32(sys.I386) + PPC64 = uint32(sys.PPC64) + S390X = uint32(sys.S390X) + ) + + switch uint32(SysArch.Family) | elftype<<24 { default: Diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype) fallthrough - case 'z' | R_390_8: - *siz = 1 + case S390X | R_390_8<<24: + return 1 - case '9' | R_PPC64_TOC16<<24, - '9' | R_PPC64_TOC16_LO<<24, - '9' | R_PPC64_TOC16_HI<<24, - '9' | R_PPC64_TOC16_HA<<24, - '9' | R_PPC64_TOC16_DS<<24, - '9' | R_PPC64_TOC16_LO_DS<<24, - '9' | R_PPC64_REL16_LO<<24, - '9' | R_PPC64_REL16_HI<<24, - '9' | R_PPC64_REL16_HA<<24, - 'z' | R_390_16<<24, - 'z' | R_390_GOT16<<24, - 'z' | R_390_PC16<<24, - 'z' | R_390_PC16DBL<<24, - 'z' | R_390_PLT16DBL<<24: - *siz = 2 + case PPC64 | R_PPC64_TOC16<<24, + PPC64 | R_PPC64_TOC16_LO<<24, + PPC64 | R_PPC64_TOC16_HI<<24, + PPC64 | R_PPC64_TOC16_HA<<24, + PPC64 | R_PPC64_TOC16_DS<<24, + PPC64 | R_PPC64_TOC16_LO_DS<<24, + PPC64 | R_PPC64_REL16_LO<<24, + PPC64 | R_PPC64_REL16_HI<<24, + PPC64 | R_PPC64_REL16_HA<<24, + S390X | R_390_16<<24, + S390X | R_390_GOT16<<24, + S390X | R_390_PC16<<24, + S390X | R_390_PC16DBL<<24, + S390X | R_390_PLT16DBL<<24: + return 2 - case '5' | R_ARM_ABS32<<24, - '5' | R_ARM_GOT32<<24, - '5' | R_ARM_PLT32<<24, - '5' | R_ARM_GOTOFF<<24, - '5' | R_ARM_GOTPC<<24, - '5' | R_ARM_THM_PC22<<24, - '5' | R_ARM_REL32<<24, - '5' | R_ARM_CALL<<24, - '5' | R_ARM_V4BX<<24, - '5' | R_ARM_GOT_PREL<<24, - '5' | R_ARM_PC24<<24, - '5' | R_ARM_JUMP24<<24, - '6' | R_X86_64_PC32<<24, - '6' | R_X86_64_PLT32<<24, - '6' | R_X86_64_GOTPCREL<<24, - '6' | R_X86_64_GOTPCRELX<<24, - '6' | R_X86_64_REX_GOTPCRELX<<24, - '8' | R_386_32<<24, - '8' | R_386_PC32<<24, - '8' | R_386_GOT32<<24, - '8' | R_386_PLT32<<24, - '8' | R_386_GOTOFF<<24, - '8' | R_386_GOTPC<<24, - '8' | R_386_GOT32X<<24, - '9' | R_PPC64_REL24<<24, - '9' | R_PPC_REL32<<24, - 'z' | R_390_32<<24, - 'z' | R_390_PC32<<24, - 'z' | R_390_GOT32<<24, - 'z' | R_390_PLT32<<24, - 'z' | R_390_PC32DBL<<24, - 'z' | R_390_PLT32DBL<<24, - 'z' | R_390_GOTPCDBL<<24, - 'z' | R_390_GOTENT<<24: - *siz = 4 + case ARM | R_ARM_ABS32<<24, + ARM | R_ARM_GOT32<<24, + ARM | R_ARM_PLT32<<24, + ARM | R_ARM_GOTOFF<<24, + ARM | R_ARM_GOTPC<<24, + ARM | R_ARM_THM_PC22<<24, + ARM | R_ARM_REL32<<24, + ARM | R_ARM_CALL<<24, + ARM | R_ARM_V4BX<<24, + ARM | R_ARM_GOT_PREL<<24, + ARM | R_ARM_PC24<<24, + ARM | R_ARM_JUMP24<<24, + AMD64 | R_X86_64_PC32<<24, + AMD64 | R_X86_64_PLT32<<24, + AMD64 | R_X86_64_GOTPCREL<<24, + AMD64 | R_X86_64_GOTPCRELX<<24, + AMD64 | R_X86_64_REX_GOTPCRELX<<24, + I386 | R_386_32<<24, + I386 | R_386_PC32<<24, + I386 | R_386_GOT32<<24, + I386 | R_386_PLT32<<24, + I386 | R_386_GOTOFF<<24, + I386 | R_386_GOTPC<<24, + I386 | R_386_GOT32X<<24, + PPC64 | R_PPC64_REL24<<24, + PPC64 | R_PPC_REL32<<24, + S390X | R_390_32<<24, + S390X | R_390_PC32<<24, + S390X | R_390_GOT32<<24, + S390X | R_390_PLT32<<24, + S390X | R_390_PC32DBL<<24, + S390X | R_390_PLT32DBL<<24, + S390X | R_390_GOTPCDBL<<24, + S390X | R_390_GOTENT<<24: + return 4 - case '6' | R_X86_64_64<<24, - '9' | R_PPC64_ADDR64<<24, - 'z' | R_390_GLOB_DAT<<24, - 'z' | R_390_RELATIVE<<24, - 'z' | R_390_GOTOFF<<24, - 'z' | R_390_GOTPC<<24, - 'z' | R_390_64<<24, - 'z' | R_390_PC64<<24, - 'z' | R_390_GOT64<<24, - 'z' | R_390_PLT64<<24: - *siz = 8 + case AMD64 | R_X86_64_64<<24, + PPC64 | R_PPC64_ADDR64<<24, + S390X | R_390_GLOB_DAT<<24, + S390X | R_390_RELATIVE<<24, + S390X | R_390_GOTOFF<<24, + S390X | R_390_GOTPC<<24, + S390X | R_390_64<<24, + S390X | R_390_PC64<<24, + S390X | R_390_GOT64<<24, + S390X | R_390_PLT64<<24: + return 8 } - - return 256 + elftype } diff --git a/src/cmd/link/internal/ld/ldmacho.go b/src/cmd/link/internal/ld/ldmacho.go index c4c13f13b9..a10124907c 100644 --- a/src/cmd/link/internal/ld/ldmacho.go +++ b/src/cmd/link/internal/ld/ldmacho.go @@ -1,9 +1,12 @@ package ld import ( + "cmd/internal/bio" "cmd/internal/obj" + "cmd/internal/sys" "encoding/binary" "fmt" + "io" "log" "sort" ) @@ -41,7 +44,7 @@ const ( ) type LdMachoObj struct { - f *obj.Biobuf + f *bio.Reader base int64 // off in f where Mach-O begins length int64 // length of Mach-O is64 bool @@ -297,7 +300,10 @@ func macholoadrel(m *LdMachoObj, sect *LdMachoSect) int { rel := make([]LdMachoRel, sect.nreloc) n := int(sect.nreloc * 8) buf := make([]byte, n) - if obj.Bseek(m.f, m.base+int64(sect.reloff), 0) < 0 || obj.Bread(m.f, buf) != n { + if m.f.Seek(m.base+int64(sect.reloff), 0) < 0 { + return -1 + } + if _, err := io.ReadFull(m.f, buf); err != nil { return -1 } var p []byte @@ -343,7 +349,10 @@ func macholoaddsym(m *LdMachoObj, d *LdMachoDysymtab) int { n := int(d.nindirectsyms) p := make([]byte, n*4) - if obj.Bseek(m.f, m.base+int64(d.indirectsymoff), 0) < 0 || obj.Bread(m.f, p) != len(p) { + if m.f.Seek(m.base+int64(d.indirectsymoff), 0) < 0 { + return -1 + } + if _, err := io.ReadFull(m.f, p); err != nil { return -1 } @@ -360,7 +369,10 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int { } strbuf := make([]byte, symtab.strsize) - if obj.Bseek(m.f, m.base+int64(symtab.stroff), 0) < 0 || obj.Bread(m.f, strbuf) != len(strbuf) { + if m.f.Seek(m.base+int64(symtab.stroff), 0) < 0 { + return -1 + } + if _, err := io.ReadFull(m.f, strbuf); err != nil { return -1 } @@ -370,7 +382,10 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int { } n := int(symtab.nsym * uint32(symsize)) symbuf := make([]byte, n) - if obj.Bseek(m.f, m.base+int64(symtab.symoff), 0) < 0 || obj.Bread(m.f, symbuf) != len(symbuf) { + if m.f.Seek(m.base+int64(symtab.symoff), 0) < 0 { + return -1 + } + if _, err := io.ReadFull(m.f, symbuf); err != nil { return -1 } sym := make([]LdMachoSym, symtab.nsym) @@ -384,8 +399,8 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int { return -1 } s.name = cstring(strbuf[v:]) - s.type_ = uint8(p[4]) - s.sectnum = uint8(p[5]) + s.type_ = p[4] + s.sectnum = p[5] s.desc = m.e.Uint16(p[6:]) if m.is64 { s.value = m.e.Uint64(p[8:]) @@ -400,7 +415,7 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int { return 0 } -func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) { +func ldmacho(f *bio.Reader, pkg string, length int64, pn string) { var err error var j int var is64 bool @@ -430,8 +445,8 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) { var name string Ctxt.IncVersion() - base := obj.Boffset(f) - if obj.Bread(f, hdr[:]) != len(hdr) { + base := f.Offset() + if _, err := io.ReadFull(f, hdr[:]); err != nil { goto bad } @@ -445,44 +460,43 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) { } is64 = e.Uint32(hdr[:]) == 0xFEEDFACF - ncmd = e.Uint32([]byte(hdr[4*4:])) - cmdsz = e.Uint32([]byte(hdr[5*4:])) + ncmd = e.Uint32(hdr[4*4:]) + cmdsz = e.Uint32(hdr[5*4:]) if ncmd > 0x10000 || cmdsz >= 0x01000000 { err = fmt.Errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz) goto bad } if is64 { - var tmp [4]uint8 - obj.Bread(f, tmp[:4]) // skip reserved word in header + f.Seek(4, 1) // skip reserved word in header } m = new(LdMachoObj) m.f = f m.e = e - m.cputype = uint(e.Uint32([]byte(hdr[1*4:]))) - m.subcputype = uint(e.Uint32([]byte(hdr[2*4:]))) - m.filetype = e.Uint32([]byte(hdr[3*4:])) + m.cputype = uint(e.Uint32(hdr[1*4:])) + m.subcputype = uint(e.Uint32(hdr[2*4:])) + m.filetype = e.Uint32(hdr[3*4:]) m.ncmd = uint(ncmd) - m.flags = e.Uint32([]byte(hdr[6*4:])) + m.flags = e.Uint32(hdr[6*4:]) m.is64 = is64 m.base = base m.length = length m.name = pn - switch Thearch.Thechar { + switch SysArch.Family { default: - Diag("%s: mach-o %s unimplemented", pn, Thestring) + Diag("%s: mach-o %s unimplemented", pn, SysArch.Name) return - case '6': + case sys.AMD64: if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 { Diag("%s: mach-o object but not amd64", pn) return } - case '8': + case sys.I386: if e != binary.LittleEndian || m.cputype != LdMachoCpu386 { Diag("%s: mach-o object but not 386", pn) return @@ -492,7 +506,7 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) { m.cmd = make([]LdMachoCmd, ncmd) off = uint32(len(hdr)) cmdp = make([]byte, cmdsz) - if obj.Bread(f, cmdp) != len(cmdp) { + if _, err2 := io.ReadFull(f, cmdp); err2 != nil { err = fmt.Errorf("reading cmds: %v", err) goto bad } @@ -555,7 +569,11 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) { } dat = make([]byte, c.seg.filesz) - if obj.Bseek(f, m.base+int64(c.seg.fileoff), 0) < 0 || obj.Bread(f, dat) != len(dat) { + if f.Seek(m.base+int64(c.seg.fileoff), 0) < 0 { + err = fmt.Errorf("cannot load object data: %v", err) + goto bad + } + if _, err2 := io.ReadFull(f, dat); err2 != nil { err = fmt.Errorf("cannot load object data: %v", err) goto bad } @@ -689,19 +707,13 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) { log.Fatalf("symbol %s listed multiple times", s.Name) } s.Attr |= AttrOnList - if Ctxt.Etextp != nil { - Ctxt.Etextp.Next = s - } else { - Ctxt.Textp = s - } - Ctxt.Etextp = s + Ctxt.Textp = append(Ctxt.Textp, s) for s1 = s.Sub; s1 != nil; s1 = s1.Sub { if s1.Attr.OnList() { log.Fatalf("symbol %s listed multiple times", s1.Name) } s1.Attr |= AttrOnList - Ctxt.Etextp.Next = s1 - Ctxt.Etextp = s1 + Ctxt.Textp = append(Ctxt.Textp, s1) } } } @@ -724,10 +736,9 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) { rp = &r[rpi] rel = §.rel[j] if rel.scattered != 0 { - if Thearch.Thechar != '8' { + if SysArch.Family != sys.I386 { // mach-o only uses scattered relocation on 32-bit platforms Diag("unexpected scattered relocation") - continue } @@ -821,7 +832,7 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) { rp.Off = int32(rel.addr) // Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0). - if Thearch.Thechar == '6' && rel.extrn == 0 && rel.type_ == 1 { + if SysArch.Family == sys.AMD64 && rel.extrn == 0 && rel.type_ == 1 { // Calculate the addend as the offset into the section. // // The rip-relative offset stored in the object file is encoded @@ -847,7 +858,7 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) { // For i386 Mach-O PC-relative, the addend is written such that // it *is* the PC being subtracted. Use that to make // it match our version of PC-relative. - if rel.pcrel != 0 && Thearch.Thechar == '8' { + if rel.pcrel != 0 && SysArch.Family == sys.I386 { rp.Add += int64(rp.Off) + int64(rp.Siz) } if rel.extrn == 0 { @@ -866,7 +877,7 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) { // include that information in the addend. // We only care about the delta from the // section base. - if Thearch.Thechar == '8' { + if SysArch.Family == sys.I386 { rp.Add -= int64(c.seg.sect[rel.symnum-1].addr) } } else { diff --git a/src/cmd/link/internal/ld/ldpe.go b/src/cmd/link/internal/ld/ldpe.go index 5c3e99c44f..7eb26bcbe8 100644 --- a/src/cmd/link/internal/ld/ldpe.go +++ b/src/cmd/link/internal/ld/ldpe.go @@ -5,9 +5,12 @@ package ld import ( + "cmd/internal/bio" "cmd/internal/obj" + "cmd/internal/sys" "encoding/binary" "fmt" + "io" "log" "sort" "strconv" @@ -116,7 +119,7 @@ type PeSect struct { } type PeObj struct { - f *obj.Biobuf + f *bio.Reader name string base uint32 sect []PeSect @@ -127,14 +130,14 @@ type PeObj struct { snames []byte } -func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) { +func ldpe(f *bio.Reader, pkg string, length int64, pn string) { if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "%5.2f ldpe %s\n", obj.Cputime(), pn) + fmt.Fprintf(Bso, "%5.2f ldpe %s\n", obj.Cputime(), pn) } var sect *PeSect Ctxt.IncVersion() - base := int32(obj.Boffset(f)) + base := f.Offset() peobj := new(PeObj) peobj.f = f @@ -172,15 +175,15 @@ func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) { // TODO return error if found .cormeta // load string table - obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0) + f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0) - if obj.Bread(f, symbuf[:4]) != 4 { + if _, err := io.ReadFull(f, symbuf[:4]); err != nil { goto bad } l = Le32(symbuf[:]) peobj.snames = make([]byte, l) - obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0) - if obj.Bread(f, peobj.snames) != len(peobj.snames) { + f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0) + if _, err := io.ReadFull(f, peobj.snames); err != nil { goto bad } @@ -200,10 +203,10 @@ func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) { peobj.pesym = make([]PeSym, peobj.fh.NumberOfSymbols) peobj.npesym = uint(peobj.fh.NumberOfSymbols) - obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable), 0) + f.Seek(base+int64(peobj.fh.PointerToSymbolTable), 0) for i := 0; uint32(i) < peobj.fh.NumberOfSymbols; i += numaux + 1 { - obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0) - if obj.Bread(f, symbuf[:]) != len(symbuf) { + f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0) + if _, err := io.ReadFull(f, symbuf[:]); err != nil { goto bad } @@ -288,10 +291,10 @@ func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) { } r = make([]Reloc, rsect.sh.NumberOfRelocations) - obj.Bseek(f, int64(peobj.base)+int64(rsect.sh.PointerToRelocations), 0) + f.Seek(int64(peobj.base)+int64(rsect.sh.PointerToRelocations), 0) for j = 0; j < int(rsect.sh.NumberOfRelocations); j++ { rp = &r[j] - if obj.Bread(f, symbuf[:10]) != 10 { + if _, err := io.ReadFull(f, symbuf[:10]); err != nil { goto bad } rva := Le32(symbuf[0:]) @@ -432,19 +435,13 @@ func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) { log.Fatalf("symbol %s listed multiple times", s.Name) } s.Attr |= AttrOnList - if Ctxt.Etextp != nil { - Ctxt.Etextp.Next = s - } else { - Ctxt.Textp = s - } - Ctxt.Etextp = s + Ctxt.Textp = append(Ctxt.Textp, s) for s = s.Sub; s != nil; s = s.Sub { if s.Attr.OnList() { log.Fatalf("symbol %s listed multiple times", s.Name) } s.Attr |= AttrOnList - Ctxt.Etextp.Next = s - Ctxt.Etextp = s + Ctxt.Textp = append(Ctxt.Textp, s) } } } @@ -464,7 +461,10 @@ func pemap(peobj *PeObj, sect *PeSect) int { if sect.sh.PointerToRawData == 0 { // .bss doesn't have data in object file return 0 } - if obj.Bseek(peobj.f, int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 || obj.Bread(peobj.f, sect.base) != len(sect.base) { + if peobj.f.Seek(int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 { + return -1 + } + if _, err := io.ReadFull(peobj.f, sect.base); err != nil { return -1 } @@ -492,7 +492,7 @@ func readpesym(peobj *PeObj, i int, y **PeSym) (err error) { if strings.HasPrefix(name, "__imp_") { name = name[6:] // __imp_Name => Name } - if Thearch.Thechar == '8' && name[0] == '_' { + if SysArch.Family == sys.I386 && name[0] == '_' { name = name[1:] // _Name => Name } } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 5616700445..53428bb1c6 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -33,7 +33,9 @@ package ld import ( "bufio" "bytes" + "cmd/internal/bio" "cmd/internal/obj" + "cmd/internal/sys" "crypto/sha1" "debug/elf" "encoding/binary" @@ -82,14 +84,9 @@ import ( // THE SOFTWARE. type Arch struct { - Thechar int - Ptrsize int - Intsize int - Regsize int Funcalign int Maxalign int Minalign int - Minlc int Dwarfregsp int Dwarfreglr int Linuxdynld string @@ -133,7 +130,6 @@ func (r *Rpath) String() string { var ( Thearch Arch - datap *LSym Debug [128]int Lcsize int32 rpath Rpath @@ -191,8 +187,7 @@ func UseRelro() bool { } var ( - Thestring string - Thelinkarch *LinkArch + SysArch *sys.Arch outfile string dynexp []*LSym dynlib []string @@ -201,6 +196,7 @@ var ( Funcalign int iscgo bool elfglobalsymndx int + flag_dumpdep bool flag_installsuffix string flag_race int flag_msan int @@ -245,9 +241,10 @@ const ( var ( headstring string // buffered output - Bso obj.Biobuf + Bso *bufio.Writer ) +// TODO(dfc) outBuf duplicates bio.Writer type outBuf struct { w *bufio.Writer f *os.File @@ -472,7 +469,7 @@ func loadinternal(name string) { if Linkshared { shlibname := filepath.Join(Ctxt.Libdir[i], name+".shlibname") if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "searching for %s.a in %s\n", name, shlibname) + fmt.Fprintf(Bso, "searching for %s.a in %s\n", name, shlibname) } if _, err := os.Stat(shlibname); err == nil { addlibpath(Ctxt, "internal", "internal", "", name, shlibname) @@ -482,7 +479,7 @@ func loadinternal(name string) { } pname := filepath.Join(Ctxt.Libdir[i], name+".a") if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "searching for %s.a in %s\n", name, pname) + fmt.Fprintf(Bso, "searching for %s.a in %s\n", name, pname) } if _, err := os.Stat(pname); err == nil { addlibpath(Ctxt, "internal", "internal", pname, name, "") @@ -492,7 +489,7 @@ func loadinternal(name string) { } if found == 0 { - fmt.Fprintf(&Bso, "warning: unable to find %s.a\n", name) + fmt.Fprintf(Bso, "warning: unable to find %s.a\n", name) } } @@ -509,7 +506,7 @@ func loadlib() { } loadinternal("runtime") - if Thearch.Thechar == '5' { + if SysArch.Family == sys.ARM { loadinternal("math") } if flag_race != 0 { @@ -524,7 +521,7 @@ func loadlib() { iscgo = iscgo || Ctxt.Library[i].Pkg == "runtime/cgo" if Ctxt.Library[i].Shlib == "" { if Debug['v'] > 1 { - fmt.Fprintf(&Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].File, Ctxt.Library[i].Objref) + fmt.Fprintf(Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].File, Ctxt.Library[i].Objref) } objfile(Ctxt.Library[i]) } @@ -533,7 +530,7 @@ func loadlib() { for i = 0; i < len(Ctxt.Library); i++ { if Ctxt.Library[i].Shlib != "" { if Debug['v'] > 1 { - fmt.Fprintf(&Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].Shlib, Ctxt.Library[i].Objref) + fmt.Fprintf(Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].Shlib, Ctxt.Library[i].Objref) } ldshlibsyms(Ctxt.Library[i].Shlib) } @@ -562,7 +559,7 @@ func loadlib() { // dependency problems when compiling natively (external linking requires // runtime/cgo, runtime/cgo requires cmd/cgo, but cmd/cgo needs to be // compiled using external linking.) - if (Thearch.Thechar == '5' || Thearch.Thechar == '7') && HEADTYPE == obj.Hdarwin && iscgo { + if SysArch.InFamily(sys.ARM, sys.ARM64) && HEADTYPE == obj.Hdarwin && iscgo { Linkmode = LinkExternal } @@ -621,7 +618,7 @@ func loadlib() { // a variable to hold g in assembly (currently only intel). if tlsg.Type == 0 { tlsg.Type = obj.STLSBSS - tlsg.Size = int64(Thearch.Ptrsize) + tlsg.Size = int64(SysArch.PtrSize) } else if tlsg.Type != obj.SDYNIMPORT { Diag("internal error: runtime declared tlsg variable %d", tlsg.Type) } @@ -639,7 +636,7 @@ func loadlib() { // In addition, on ARM, the runtime depends on the linker // recording the value of GOARM. - if Thearch.Thechar == '5' { + if SysArch.Family == sys.ARM { s := Linklookup(Ctxt, "runtime.goarm", 0) s.Type = obj.SRODATA @@ -696,13 +693,13 @@ func loadlib() { args := hostlinkArchArgs() args = append(args, "--print-libgcc-file-name") if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "%s %v\n", extld, args) + fmt.Fprintf(Bso, "%s %v\n", extld, args) } out, err := exec.Command(extld, args...).Output() if err != nil { if Debug['v'] != 0 { - fmt.Fprintln(&Bso, "not using a libgcc file because compiler failed") - fmt.Fprintf(&Bso, "%v\n%s\n", err, out) + fmt.Fprintln(Bso, "not using a libgcc file because compiler failed") + fmt.Fprintf(Bso, "%v\n%s\n", err, out) } libgccfile = "none" } else { @@ -743,17 +740,17 @@ func loadlib() { * look for the next file in an archive. * adapted from libmach. */ -func nextar(bp *obj.Biobuf, off int64, a *ArHdr) int64 { +func nextar(bp *bio.Reader, off int64, a *ArHdr) int64 { if off&1 != 0 { off++ } - obj.Bseek(bp, off, 0) - buf := make([]byte, SAR_HDR) - if n := obj.Bread(bp, buf); n < len(buf) { - if n >= 0 { - return 0 + bp.Seek(off, 0) + var buf [SAR_HDR]byte + if n, err := io.ReadFull(bp, buf[:]); err != nil { + if n == 0 && err != io.EOF { + return -1 } - return -1 + return 0 } a.name = artrim(buf[0:16]) @@ -768,35 +765,38 @@ func nextar(bp *obj.Biobuf, off int64, a *ArHdr) int64 { if arsize&1 != 0 { arsize++ } - return int64(arsize) + SAR_HDR + return arsize + SAR_HDR } func objfile(lib *Library) { pkg := pathtoprefix(lib.Pkg) if Debug['v'] > 1 { - fmt.Fprintf(&Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), lib.File, pkg) + fmt.Fprintf(Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), lib.File, pkg) } Bso.Flush() - f, err := obj.Bopenr(lib.File) + f, err := bio.Open(lib.File) if err != nil { Exitf("cannot open file %s: %v", lib.File, err) } - magbuf := make([]byte, len(ARMAG)) - if obj.Bread(f, magbuf) != len(magbuf) || !strings.HasPrefix(string(magbuf), ARMAG) { + for i := 0; i < len(ARMAG); i++ { + if c, err := f.ReadByte(); err == nil && c == ARMAG[i] { + continue + } + /* load it as a regular file */ - l := obj.Bseek(f, 0, 2) + l := f.Seek(0, 2) - obj.Bseek(f, 0, 0) + f.Seek(0, 0) ldobj(f, pkg, l, lib.File, lib.File, FileObj) - obj.Bterm(f) + f.Close() return } /* process __.PKGDEF */ - off := obj.Boffset(f) + off := f.Offset() var arhdr ArHdr l := nextar(f, off, &arhdr) @@ -812,12 +812,14 @@ func objfile(lib *Library) { } if Buildmode == BuildmodeShared { - before := obj.Boffset(f) + before := f.Offset() pkgdefBytes := make([]byte, atolwhex(arhdr.size)) - obj.Bread(f, pkgdefBytes) + if _, err := io.ReadFull(f, pkgdefBytes); err != nil { + Diag("%s: short read on archive file symbol header: %v", lib.File, err) + } hash := sha1.Sum(pkgdefBytes) lib.hash = hash[:] - obj.Bseek(f, before, 0) + f.Seek(before, 0) } off += l @@ -853,11 +855,11 @@ func objfile(lib *Library) { } out: - obj.Bterm(f) + f.Close() } type Hostobj struct { - ld func(*obj.Biobuf, string, int64, string) + ld func(*bio.Reader, string, int64, string) pkg string pn string file string @@ -878,7 +880,7 @@ var internalpkg = []string{ "runtime/msan", } -func ldhostobj(ld func(*obj.Biobuf, string, int64, string), f *obj.Biobuf, pkg string, length int64, pn string, file string) *Hostobj { +func ldhostobj(ld func(*bio.Reader, string, int64, string), f *bio.Reader, pkg string, length int64, pn string, file string) *Hostobj { isinternal := false for i := 0; i < len(internalpkg); i++ { if pkg == internalpkg[i] { @@ -909,26 +911,24 @@ func ldhostobj(ld func(*obj.Biobuf, string, int64, string), f *obj.Biobuf, pkg s h.pkg = pkg h.pn = pn h.file = file - h.off = obj.Boffset(f) + h.off = f.Offset() h.length = length return h } func hostobjs() { - var f *obj.Biobuf var h *Hostobj for i := 0; i < len(hostobj); i++ { h = &hostobj[i] - var err error - f, err = obj.Bopenr(h.file) - if f == nil { + f, err := bio.Open(h.file) + if err != nil { Exitf("cannot reopen %s: %v", h.pn, err) } - obj.Bseek(f, h.off, 0) + f.Seek(h.off, 0) h.ld(f, h.pkg, h.length, h.pn) - obj.Bterm(f) + f.Close() } } @@ -1040,7 +1040,7 @@ func archive() { argv = append(argv, hostobjCopy()...) if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "archive: %s\n", strings.Join(argv, " ")) + fmt.Fprintf(Bso, "archive: %s\n", strings.Join(argv, " ")) Bso.Flush() } @@ -1117,6 +1117,23 @@ func hostlink() { // because lazy PLT resolution can use large amounts of stack at // times we cannot allow it to do so. argv = append(argv, "-Wl,-znow") + + // Do not let the host linker generate COPY relocations. These + // can move symbols out of sections that rely on stable offsets + // from the beginning of the section (like STYPE). + argv = append(argv, "-Wl,-znocopyreloc") + + if SysArch.InFamily(sys.ARM, sys.ARM64) { + // On ARM, the GNU linker will generate COPY relocations + // even with -znocopyreloc set. + // https://sourceware.org/bugzilla/show_bug.cgi?id=19962 + // + // On ARM64, the GNU linker will fail instead of + // generating COPY relocations. + // + // In both cases, switch to gold. + argv = append(argv, "-fuse-ld=gold") + } } if Iself && len(buildinfo) > 0 { @@ -1187,6 +1204,24 @@ func hostlink() { argv = append(argv, ldflag...) + if flag_race != 0 { + // On a system where the toolchain creates position independent + // executables by default, tsan initialization can fail. So we pass + // -no-pie here, but support for that flag is quite new and we test + // for its support first. + src := filepath.Join(tmpdir, "trivial.c") + if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil { + Ctxt.Diag("WriteFile trivial.c failed: %v", err) + } + cmd := exec.Command(argv[0], "-no-pie", "trivial.c") + cmd.Dir = tmpdir + out, err := cmd.CombinedOutput() + supported := err == nil && !bytes.Contains(out, []byte("unrecognized")) + if supported { + argv = append(argv, "-no-pie") + } + } + for _, p := range strings.Fields(extldflags) { argv = append(argv, p) @@ -1209,24 +1244,24 @@ func hostlink() { } if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "host link:") + fmt.Fprintf(Bso, "host link:") for _, v := range argv { - fmt.Fprintf(&Bso, " %q", v) + fmt.Fprintf(Bso, " %q", v) } - fmt.Fprintf(&Bso, "\n") + fmt.Fprintf(Bso, "\n") Bso.Flush() } if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil { Exitf("running %s failed: %v\n%s", argv[0], err, out) } else if Debug['v'] != 0 && len(out) > 0 { - fmt.Fprintf(&Bso, "%s", out) + fmt.Fprintf(Bso, "%s", out) Bso.Flush() } if Debug['s'] == 0 && debug_s == 0 && HEADTYPE == obj.Hdarwin { // Skip combining dwarf on arm. - if Thearch.Thechar != '5' && Thearch.Thechar != '7' { + if !SysArch.InFamily(sys.ARM, sys.ARM64) { dsym := filepath.Join(tmpdir, "go.dwarf") if out, err := exec.Command("dsymutil", "-f", outfile, "-o", dsym).CombinedOutput(); err != nil { Ctxt.Cursym = nil @@ -1254,14 +1289,14 @@ func hostlink() { // hostlinkArchArgs returns arguments to pass to the external linker // based on the architecture. func hostlinkArchArgs() []string { - switch Thearch.Thechar { - case '8': + switch SysArch.Family { + case sys.I386: return []string{"-m32"} - case '6', '9', 'z': + case sys.AMD64, sys.PPC64, sys.S390X: return []string{"-m64"} - case '5': + case sys.ARM: return []string{"-marm"} - case '7': + case sys.ARM64: // nothing needed } return nil @@ -1270,15 +1305,15 @@ func hostlinkArchArgs() []string { // ldobj loads an input object. If it is a host object (an object // compiled by a non-Go compiler) it returns the Hostobj pointer. If // it is a Go object, it returns nil. -func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, whence int) *Hostobj { - eof := obj.Boffset(f) + length +func ldobj(f *bio.Reader, pkg string, length int64, pn string, file string, whence int) *Hostobj { + eof := f.Offset() + length - start := obj.Boffset(f) - c1 := obj.Bgetc(f) - c2 := obj.Bgetc(f) - c3 := obj.Bgetc(f) - c4 := obj.Bgetc(f) - obj.Bseek(f, start, 0) + start := f.Offset() + c1 := bgetc(f) + c2 := bgetc(f) + c3 := bgetc(f) + c4 := bgetc(f) + f.Seek(start, 0) magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4) if magic == 0x7f454c46 { // \x7F E L F @@ -1294,22 +1329,19 @@ func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, when } /* check the header */ - line := obj.Brdline(f, '\n') - if line == "" { - if obj.Blinelen(f) > 0 { - Diag("%s: not an object file", pn) - return nil - } - Diag("truncated object file: %s", pn) + line, err := f.ReadString('\n') + if err != nil { + Diag("truncated object file: %s: %v", pn, err) return nil } if !strings.HasPrefix(line, "go object ") { if strings.HasSuffix(pn, ".go") { - Exitf("%cl: input %s is not .%c file (use %cg to compile .go files)", Thearch.Thechar, pn, Thearch.Thechar, Thearch.Thechar) + Exitf("%s: uncompiled .go source file", pn) + return nil } - if line == Thestring { + if line == SysArch.Name { // old header format: just $GOOS Diag("%s: stale object file", pn) return nil @@ -1341,28 +1373,28 @@ func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, when } /* skip over exports and other info -- ends with \n!\n */ - import0 := obj.Boffset(f) + import0 := f.Offset() c1 = '\n' // the last line ended in \n - c2 = obj.Bgetc(f) - c3 = obj.Bgetc(f) + c2 = bgetc(f) + c3 = bgetc(f) for c1 != '\n' || c2 != '!' || c3 != '\n' { c1 = c2 c2 = c3 - c3 = obj.Bgetc(f) - if c3 == obj.Beof { + c3 = bgetc(f) + if c3 == -1 { Diag("truncated object file: %s", pn) return nil } } - import1 := obj.Boffset(f) + import1 := f.Offset() - obj.Bseek(f, import0, 0) + f.Seek(import0, 0) ldpkg(f, pkg, import1-import0-2, pn, whence) // -2 for !\n - obj.Bseek(f, import1, 0) + f.Seek(import1, 0) - LoadObjFile(Ctxt, f, pkg, eof-obj.Boffset(f), pn) + LoadObjFile(Ctxt, f, pkg, eof-f.Offset(), pn) return nil } @@ -1500,12 +1532,12 @@ func ldshlibsyms(shlib string) { // the type data. if strings.HasPrefix(lsym.Name, "type.") && !strings.HasPrefix(lsym.Name, "type..") { lsym.P = readelfsymboldata(f, &elfsym) - gcdata_locations[elfsym.Value+2*uint64(Thearch.Ptrsize)+8+1*uint64(Thearch.Ptrsize)] = lsym + gcdata_locations[elfsym.Value+2*uint64(SysArch.PtrSize)+8+1*uint64(SysArch.PtrSize)] = lsym } } } gcdata_addresses := make(map[*LSym]uint64) - if Thearch.Thechar == '7' { + if SysArch.Family == sys.ARM64 { for _, sect := range f.Sections { if sect.Type == elf.SHT_RELA { var rela elf.Rela64 @@ -1532,30 +1564,14 @@ func ldshlibsyms(shlib string) { // We might have overwritten some functions above (this tends to happen for the // autogenerated type equality/hashing functions) and we don't want to generated - // pcln table entries for these any more so unstitch them from the Textp linked - // list. - var last *LSym - - for s := Ctxt.Textp; s != nil; s = s.Next { - if s.Type == obj.SDYNIMPORT { - continue - } - - if last == nil { - Ctxt.Textp = s - } else { - last.Next = s + // pcln table entries for these any more so remove them from Textp. + textp := make([]*LSym, 0, len(Ctxt.Textp)) + for _, s := range Ctxt.Textp { + if s.Type != obj.SDYNIMPORT { + textp = append(textp, s) } - last = s - } - - if last == nil { - Ctxt.Textp = nil - Ctxt.Etextp = nil - } else { - last.Next = nil - Ctxt.Etextp = last } + Ctxt.Textp = textp Ctxt.Shlibs = append(Ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f, gcdata_addresses: gcdata_addresses}) } @@ -1564,10 +1580,6 @@ func mywhatsys() { goroot = obj.Getgoroot() goos = obj.Getgoos() goarch = obj.Getgoarch() - - if !strings.HasPrefix(goarch, Thestring) { - log.Fatalf("cannot use %cc with GOARCH=%s", Thearch.Thechar, goarch) - } } // Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync. @@ -1608,7 +1620,7 @@ func addsection(seg *Segment, name string, rwx int) *Section { sect.Rwx = uint8(rwx) sect.Name = name sect.Seg = seg - sect.Align = int32(Thearch.Ptrsize) // everything is at least pointer-aligned + sect.Align = int32(SysArch.PtrSize) // everything is at least pointer-aligned *l = sect return sect } @@ -1652,7 +1664,7 @@ func callsize() int { if haslinkregister() { return 0 } - return Thearch.Regsize + return SysArch.RegSize } func dostkcheck() { @@ -1673,7 +1685,7 @@ func dostkcheck() { // Check every function, but do the nosplit functions in a first pass, // to make the printed failure chains as short as possible. - for s := Ctxt.Textp; s != nil; s = s.Next { + for _, s := range Ctxt.Textp { // runtime.racesymbolizethunk is called from gcc-compiled C // code running on the operating system thread stack. // It uses more than the usual amount of stack but that's okay. @@ -1688,7 +1700,7 @@ func dostkcheck() { } } - for s := Ctxt.Textp; s != nil; s = s.Next { + for _, s := range Ctxt.Textp { if !s.Attr.NoSplit() { Ctxt.Cursym = s ch.sym = s @@ -1717,7 +1729,7 @@ func stkcheck(up *Chain, depth int) int { return -1 } - if s.Attr.External() || s.Pcln == nil { + if s.Attr.External() || s.FuncInfo == nil { // external function. // should never be called directly. // only diagnose the direct caller. @@ -1754,7 +1766,11 @@ func stkcheck(up *Chain, depth int) int { return 0 } // Raise limit to allow frame. - limit = int(obj.StackLimit+s.Locals) + int(Ctxt.FixedFrameSize()) + locals := int32(0) + if s.FuncInfo != nil { + locals = s.FuncInfo.Locals + } + limit = int(obj.StackLimit+locals) + int(Ctxt.FixedFrameSize()) } // Walk through sp adjustments in function, consuming relocs. @@ -1764,7 +1780,7 @@ func stkcheck(up *Chain, depth int) int { var ch1 Chain var pcsp Pciter var r *Reloc - for pciterinit(Ctxt, &pcsp, &s.Pcln.Pcsp); pcsp.done == 0; pciternext(&pcsp) { + for pciterinit(Ctxt, &pcsp, &s.FuncInfo.Pcsp); pcsp.done == 0; pciternext(&pcsp) { // pcsp.value is in effect for [pcsp.pc, pcsp.nextpc). // Check stack size in effect for this span. @@ -1956,7 +1972,7 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) { continue } if len(s.P) > 0 { - Diag("%s should not be bss (size=%d type=%d special=%v)", s.Name, int(len(s.P)), s.Type, s.Attr.Special()) + Diag("%s should not be bss (size=%d type=%d special=%v)", s.Name, len(s.P), s.Type, s.Attr.Special()) } put(s, s.Name, 'B', Symaddr(s), s.Size, int(s.Version), s.Gotype) @@ -1982,13 +1998,20 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) { } var off int32 - for s := Ctxt.Textp; s != nil; s = s.Next { + for _, s := range Ctxt.Textp { put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), s.Gotype) + locals := int32(0) + if s.FuncInfo != nil { + locals = s.FuncInfo.Locals + } // NOTE(ality): acid can't produce a stack trace without .frame symbols - put(nil, ".frame", 'm', int64(s.Locals)+int64(Thearch.Ptrsize), 0, 0, nil) + put(nil, ".frame", 'm', int64(locals)+int64(SysArch.PtrSize), 0, 0, nil) - for _, a := range s.Autom { + if s.FuncInfo == nil { + continue + } + for _, a := range s.FuncInfo.Autom { // Emit a or p according to actual offset, even if label is wrong. // This avoids negative offsets, which cannot be encoded. if a.Name != obj.A_AUTO && a.Name != obj.A_PARAM { @@ -1999,7 +2022,7 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) { if a.Name == obj.A_PARAM { off = a.Aoffset } else { - off = a.Aoffset - int32(Thearch.Ptrsize) + off = a.Aoffset - int32(SysArch.PtrSize) } // FP @@ -2009,8 +2032,8 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) { } // SP - if off <= int32(-Thearch.Ptrsize) { - put(nil, a.Asym.Name, 'a', -(int64(off) + int64(Thearch.Ptrsize)), 0, 0, a.Gotype) + if off <= int32(-SysArch.PtrSize) { + put(nil, a.Asym.Name, 'a', -(int64(off) + int64(SysArch.PtrSize)), 0, 0, a.Gotype) continue } } @@ -2019,7 +2042,7 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) { // Otherwise, off is addressing the saved program counter. // Something underhanded is going on. Say nothing. if Debug['v'] != 0 || Debug['n'] != 0 { - fmt.Fprintf(&Bso, "%5.2f symsize = %d\n", obj.Cputime(), uint32(Symsize)) + fmt.Fprintf(Bso, "%5.2f symsize = %d\n", obj.Cputime(), uint32(Symsize)) } Bso.Flush() } @@ -2085,10 +2108,10 @@ func undefsym(s *LSym) { } func undef() { - for s := Ctxt.Textp; s != nil; s = s.Next { + for _, s := range Ctxt.Textp { undefsym(s) } - for s := datap; s != nil; s = s.Next { + for _, s := range datap { undefsym(s) } if nerrors > 0 { @@ -2103,14 +2126,14 @@ func callgraph() { var i int var r *Reloc - for s := Ctxt.Textp; s != nil; s = s.Next { + for _, s := range Ctxt.Textp { for i = 0; i < len(s.R); i++ { r = &s.R[i] if r.Sym == nil { continue } if (r.Type == obj.R_CALL || r.Type == obj.R_CALLARM || r.Type == obj.R_CALLPOWER || r.Type == obj.R_CALLMIPS) && r.Sym.Type == obj.STEXT { - fmt.Fprintf(&Bso, "%s calls %s\n", s.Name, r.Sym.Name) + fmt.Fprintf(Bso, "%s calls %s\n", s.Name, r.Sym.Name) } } } @@ -2145,3 +2168,14 @@ func Rnd(v int64, r int64) int64 { v -= c return v } + +func bgetc(r *bio.Reader) int { + c, err := r.ReadByte() + if err != nil { + if err != io.EOF { + log.Fatalf("reading input: %v", err) + } + return -1 + } + return int(c) +} diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index 67a855933e..d0515d4617 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -31,9 +31,9 @@ package ld import ( - "cmd/internal/obj" + "bufio" + "cmd/internal/sys" "debug/elf" - "encoding/binary" "fmt" ) @@ -50,8 +50,6 @@ type LSym struct { Align int32 Elfsym int32 LocalElfsym int32 - Args int32 - Locals int32 Value int64 Size int64 // ElfType is set for symbols read from shared libraries by ldshlibsyms. It @@ -67,8 +65,7 @@ type LSym struct { Dynimplib string Dynimpvers string Sect *Section - Autom []Auto - Pcln *Pcln + FuncInfo *FuncInfo P []byte R []Reloc } @@ -161,13 +158,11 @@ type Shlib struct { } type Link struct { - Thechar int32 - Thestring string Goarm int32 Headtype int - Arch *LinkArch + Arch *sys.Arch Debugvlog int32 - Bso *obj.Biobuf + Bso *bufio.Writer Windows int32 Goroot string @@ -183,10 +178,8 @@ type Link struct { Diag func(string, ...interface{}) Cursym *LSym Version int - Textp *LSym - Etextp *LSym - Nhistfile int32 - Filesyms *LSym + Textp []*LSym + Filesyms []*LSym Moduledata *LSym LSymBatch []LSym } @@ -196,15 +189,15 @@ type Link struct { // on the stack in the function prologue and so always have a pointer between // the hardware stack pointer and the local variable area. func (ctxt *Link) FixedFrameSize() int64 { - switch ctxt.Arch.Thechar { - case '6', '8': + switch ctxt.Arch.Family { + case sys.AMD64, sys.I386: return 0 - case '9': + case sys.PPC64: // PIC code on ppc64le requires 32 bytes of stack, and it's easier to // just use that much stack always on ppc64x. - return int64(4 * ctxt.Arch.Ptrsize) + return int64(4 * ctxt.Arch.PtrSize) default: - return int64(ctxt.Arch.Ptrsize) + return int64(ctxt.Arch.PtrSize) } } @@ -213,15 +206,6 @@ func (l *Link) IncVersion() { l.Hash = append(l.Hash, make(map[string]*LSym)) } -type LinkArch struct { - ByteOrder binary.ByteOrder - Name string - Thechar int - Minlc int - Ptrsize int - Regsize int -} - type Library struct { Objref string Srcref string @@ -231,7 +215,10 @@ type Library struct { hash []byte } -type Pcln struct { +type FuncInfo struct { + Args int32 + Locals int32 + Autom []Auto Pcsp Pcdata Pcfile Pcdata Pcline Pcdata diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index d60203fb91..53cc96275d 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -6,6 +6,7 @@ package ld import ( "cmd/internal/obj" + "cmd/internal/sys" "sort" "strings" ) @@ -78,6 +79,8 @@ const ( MACHO_X86_64_RELOC_SIGNED_2 = 7 MACHO_X86_64_RELOC_SIGNED_4 = 8 MACHO_ARM_RELOC_VANILLA = 0 + MACHO_ARM_RELOC_PAIR = 1 + MACHO_ARM_RELOC_SECTDIFF = 2 MACHO_ARM_RELOC_BR24 = 5 MACHO_ARM64_RELOC_UNSIGNED = 0 MACHO_ARM64_RELOC_BRANCH26 = 2 @@ -131,15 +134,7 @@ var nsortsym int var load_budget int = INITIAL_MACHO_HEADR - 2*1024 func Machoinit() { - switch Thearch.Thechar { - // 64-bit architectures - case '6', '7', '9': - macho64 = true - - // 32-bit architectures - default: - break - } + macho64 = SysArch.RegSize == 8 } func getMachoHdr() *MachoHdr { @@ -356,9 +351,10 @@ func machoshbits(mseg *MachoSeg, sect *Section, segname string) { buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1) var msect *MachoSect - if sect.Rwx&1 == 0 && (Thearch.Thechar == '7' || // arm64 - (Thearch.Thechar == '6' && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive))) { // amd64 - // Darwin external linker on arm64 and on amd64 in c-shared/c-archive buildmode + if sect.Rwx&1 == 0 && segname != "__DWARF" && (SysArch.Family == sys.ARM64 || + (SysArch.Family == sys.AMD64 && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive)) || + (SysArch.Family == sys.ARM && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive))) { + // 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 // executable, put it in __DATA segment. msect = newMachoSect(mseg, buf, "__DATA") @@ -411,6 +407,10 @@ func machoshbits(mseg *MachoSeg, sect *Section, segname string) { msect.name = "__mod_init_func" msect.flag = 9 // S_MOD_INIT_FUNC_POINTERS } + + if segname == "__DWARF" { + msect.flag |= 0x02000000 + } } func Asmbmacho() { @@ -418,23 +418,23 @@ func Asmbmacho() { va := INITTEXT - int64(HEADR) mh := getMachoHdr() - switch Thearch.Thechar { + switch SysArch.Family { default: - Exitf("unknown macho architecture: %v", Thearch.Thechar) + Exitf("unknown macho architecture: %v", SysArch.Family) - case '5': + case sys.ARM: mh.cpu = MACHO_CPU_ARM mh.subcpu = MACHO_SUBCPU_ARMV7 - case '6': + case sys.AMD64: mh.cpu = MACHO_CPU_AMD64 mh.subcpu = MACHO_SUBCPU_X86 - case '7': + case sys.ARM64: mh.cpu = MACHO_CPU_ARM64 mh.subcpu = MACHO_SUBCPU_ARM64_ALL - case '8': + case sys.I386: mh.cpu = MACHO_CPU_386 mh.subcpu = MACHO_SUBCPU_X86 } @@ -445,7 +445,7 @@ func Asmbmacho() { ms = newMachoSeg("", 40) ms.fileoffset = Segtext.Fileoff - if Thearch.Thechar == '5' || Buildmode == BuildmodeCArchive { + if SysArch.Family == sys.ARM || Buildmode == BuildmodeCArchive { ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff } else { ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff @@ -492,32 +492,46 @@ func Asmbmacho() { machoshbits(ms, sect, "__DATA") } + /* dwarf */ + if Debug['w'] == 0 { + if Linkmode != LinkExternal { + ms = newMachoSeg("__DWARF", 20) + ms.vaddr = Segdwarf.Vaddr + ms.vsize = 0 + ms.fileoffset = Segdwarf.Fileoff + ms.filesize = Segdwarf.Filelen + } + for sect := Segdwarf.Sect; sect != nil; sect = sect.Next { + machoshbits(ms, sect, "__DWARF") + } + } + if Linkmode != LinkExternal { - switch Thearch.Thechar { + switch SysArch.Family { default: - Exitf("unknown macho architecture: %v", Thearch.Thechar) + Exitf("unknown macho architecture: %v", SysArch.Family) - case '5': + case sys.ARM: ml := newMachoLoad(5, 17+2) /* unix thread */ ml.data[0] = 1 /* thread type */ ml.data[1] = 17 /* word count */ ml.data[2+15] = uint32(Entryvalue()) /* start pc */ - case '6': + case sys.AMD64: ml := newMachoLoad(5, 42+2) /* unix thread */ ml.data[0] = 4 /* thread type */ ml.data[1] = 42 /* word count */ ml.data[2+32] = uint32(Entryvalue()) /* start pc */ ml.data[2+32+1] = uint32(Entryvalue() >> 32) - case '7': + case sys.ARM64: ml := newMachoLoad(5, 68+2) /* unix thread */ ml.data[0] = 6 /* thread type */ ml.data[1] = 68 /* word count */ ml.data[2+64] = uint32(Entryvalue()) /* start pc */ ml.data[2+64+1] = uint32(Entryvalue() >> 32) - case '8': + case sys.I386: ml := newMachoLoad(5, 16+2) /* unix thread */ ml.data[0] = 1 /* thread type */ ml.data[1] = 16 /* word count */ @@ -528,7 +542,6 @@ func Asmbmacho() { if Debug['d'] == 0 { // must match domacholink below s1 := Linklookup(Ctxt, ".machosymtab", 0) - s2 := Linklookup(Ctxt, ".linkedit.plt", 0) s3 := Linklookup(Ctxt, ".linkedit.got", 0) s4 := Linklookup(Ctxt, ".machosymstr", 0) @@ -576,21 +589,13 @@ func Asmbmacho() { // and we can assume OS X. // // See golang.org/issues/12941. - const ( - LC_VERSION_MIN_MACOSX = 0x24 - LC_VERSION_MIN_IPHONEOS = 0x25 - LC_VERSION_MIN_WATCHOS = 0x30 - ) + const LC_VERSION_MIN_MACOSX = 0x24 + ml := newMachoLoad(LC_VERSION_MIN_MACOSX, 2) ml.data[0] = 10<<16 | 7<<8 | 0<<0 // OS X version 10.7.0 ml.data[1] = 10<<16 | 7<<8 | 0<<0 // SDK 10.7.0 } - // TODO: dwarf headers go in ms too - if Debug['s'] == 0 { - dwarfaddmachoheaders(ms) - } - a := machowrite() if int32(a) > HEADR { Exitf("HEADR too small: %d > %d", a, HEADR) @@ -680,15 +685,11 @@ func machosymorder() { } func machosymtab() { - var s *LSym - var o *LSym - var p string - symtab := Linklookup(Ctxt, ".machosymtab", 0) symstr := Linklookup(Ctxt, ".machosymstr", 0) for i := 0; i < nsortsym; i++ { - s = sortsym[i] + s := sortsym[i] Adduint32(Ctxt, symtab, uint32(symstr.Size)) // Only add _ to C symbols. Go symbols have dot in the name. @@ -697,33 +698,20 @@ func machosymtab() { } // replace "·" as ".", because DTrace cannot handle it. - if !strings.Contains(s.Extname, "·") { - Addstring(symstr, s.Extname) - } else { - for p = s.Extname; p != ""; p = p[1:] { - if uint8(p[0]) == 0xc2 && uint8((p[1:])[0]) == 0xb7 { - Adduint8(Ctxt, symstr, '.') - p = p[1:] - } else { - Adduint8(Ctxt, symstr, uint8(p[0])) - } - } - - Adduint8(Ctxt, symstr, '\x00') - } + Addstring(symstr, strings.Replace(s.Extname, "·", ".", -1)) if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ { Adduint8(Ctxt, symtab, 0x01) // type N_EXT, external symbol Adduint8(Ctxt, symtab, 0) // no section Adduint16(Ctxt, symtab, 0) // desc - adduintxx(Ctxt, symtab, 0, Thearch.Ptrsize) // no value + adduintxx(Ctxt, symtab, 0, SysArch.PtrSize) // no value } else { if s.Attr.CgoExport() { Adduint8(Ctxt, symtab, 0x0f) } else { Adduint8(Ctxt, symtab, 0x0e) } - o = s + o := s for o.Outer != nil { o = o.Outer } @@ -734,7 +722,7 @@ func machosymtab() { Adduint8(Ctxt, symtab, uint8(o.Sect.Extnum)) } Adduint16(Ctxt, symtab, 0) // desc - adduintxx(Ctxt, symtab, uint64(Symaddr(s)), Thearch.Ptrsize) + adduintxx(Ctxt, symtab, uint64(Symaddr(s)), SysArch.PtrSize) } } } @@ -821,27 +809,25 @@ func Domacholink() int64 { return Rnd(int64(size), int64(INITRND)) } -func machorelocsect(sect *Section, first *LSym) { +func machorelocsect(sect *Section, syms []*LSym) { // If main section has no bits, nothing to relocate. if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { return } sect.Reloff = uint64(Cpos()) - var sym *LSym - for sym = first; sym != nil; sym = sym.Next { - if !sym.Attr.Reachable() { + for i, s := range syms { + if !s.Attr.Reachable() { continue } - if uint64(sym.Value) >= sect.Vaddr { + if uint64(s.Value) >= sect.Vaddr { + syms = syms[i:] break } } eaddr := int32(sect.Vaddr + sect.Length) - var r *Reloc - var ri int - for ; sym != nil; sym = sym.Next { + for _, sym := range syms { if !sym.Attr.Reachable() { continue } @@ -850,8 +836,8 @@ func machorelocsect(sect *Section, first *LSym) { } Ctxt.Cursym = sym - for ri = 0; ri < len(sym.R); ri++ { - r = &sym.R[ri] + for ri := 0; ri < len(sym.R); ri++ { + r := &sym.R[ri] if r.Done != 0 { continue } @@ -876,5 +862,7 @@ func Machoemitreloc() { for sect := Segdata.Sect; sect != nil; sect = sect.Next { machorelocsect(sect, datap) } - dwarfemitreloc() + for sect := Segdwarf.Sect; sect != nil; sect = sect.Next { + machorelocsect(sect, list2slice(dwarfp)) + } } diff --git a/src/cmd/link/internal/ld/macho_combine_dwarf.go b/src/cmd/link/internal/ld/macho_combine_dwarf.go index b5a5a8d429..dcc371ec05 100644 --- a/src/cmd/link/internal/ld/macho_combine_dwarf.go +++ b/src/cmd/link/internal/ld/macho_combine_dwarf.go @@ -15,11 +15,9 @@ import ( "unsafe" ) -var fakedwarf, realdwarf, linkseg *macho.Segment +var realdwarf, linkseg *macho.Segment var dwarfstart, linkstart int64 var linkoffset uint32 -var machHeader *macho.FileHeader -var mappedHeader []byte const ( LC_ID_DYLIB = 0xd diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go index 8a406d17a6..bcfe52585f 100644 --- a/src/cmd/link/internal/ld/objfile.go +++ b/src/cmd/link/internal/ld/objfile.go @@ -110,7 +110,10 @@ package ld import ( "bufio" "bytes" + "cmd/internal/bio" "cmd/internal/obj" + "crypto/sha1" + "encoding/base64" "io" "log" "strconv" @@ -146,18 +149,18 @@ type objReader struct { file []*LSym } -func LoadObjFile(ctxt *Link, f *obj.Biobuf, pkg string, length int64, pn string) { - start := obj.Boffset(f) +func LoadObjFile(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) { + start := f.Offset() r := &objReader{ - rd: f.Reader(), + rd: f.Reader, pkg: pkg, ctxt: ctxt, pn: pn, dupSym: &LSym{Name: ".dup"}, } r.loadObjFile() - if obj.Boffset(f) != start+length { - log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(obj.Boffset(f)), int64(start+length)) + if f.Offset() != start+length { + log.Fatalf("%s: unexpected end at %d, want %d", pn, f.Offset(), start+length) } } @@ -330,8 +333,11 @@ overwrite: } if s.Type == obj.STEXT { - s.Args = r.readInt32() - s.Locals = r.readInt32() + s.FuncInfo = new(FuncInfo) + pc := s.FuncInfo + + pc.Args = r.readInt32() + pc.Locals = r.readInt32() if r.readUint8() != 0 { s.Attr |= AttrNoSplit } @@ -340,13 +346,13 @@ overwrite: s.Attr |= AttrReflectMethod } n := r.readInt() - s.Autom = r.autom[:n:n] + pc.Autom = r.autom[:n:n] if !isdup { r.autom = r.autom[n:] } for i := 0; i < n; i++ { - s.Autom[i] = Auto{ + pc.Autom[i] = Auto{ Asym: r.readSymIndex(), Aoffset: r.readInt32(), Name: r.readInt16(), @@ -354,8 +360,6 @@ overwrite: } } - s.Pcln = new(Pcln) - pc := s.Pcln pc.Pcsp.P = r.readData() pc.Pcfile.P = r.readData() pc.Pcline.P = r.readData() @@ -394,12 +398,7 @@ overwrite: log.Fatalf("symbol %s listed multiple times", s.Name) } s.Attr |= AttrOnList - if r.ctxt.Etextp != nil { - r.ctxt.Etextp.Next = s - } else { - r.ctxt.Textp = s - } - r.ctxt.Etextp = s + r.ctxt.Textp = append(r.ctxt.Textp, s) } } } @@ -470,7 +469,7 @@ func (r *objReader) readInt64() int64 { } } - return int64(uv>>1) ^ (int64(uint64(uv)<<63) >> 63) + return int64(uv>>1) ^ (int64(uv<<63) >> 63) } func (r *objReader) readInt() int { @@ -529,13 +528,18 @@ func (r *objReader) readSymName() string { r.readInt64() return "" } - origName, err := r.rd.Peek(n) - if err != nil { - log.Fatalf("%s: unexpectedly long symbol name", r.pn) - } if cap(r.rdBuf) < n { r.rdBuf = make([]byte, 2*n) } + origName, err := r.rd.Peek(n) + if err == bufio.ErrBufferFull { + // Long symbol names are rare but exist. One source is type + // symbols for types with long string forms. See #15104. + origName = make([]byte, n) + r.readFull(origName) + } else if err != nil { + log.Fatalf("%s: error reading symbol: %v", err) + } adjName := r.rdBuf[:0] for { i := bytes.Index(origName, emptyPkg) @@ -544,8 +548,32 @@ func (r *objReader) readSymName() string { // Read past the peeked origName, now that we're done with it, // using the rfBuf (also no longer used) as the scratch space. // TODO: use bufio.Reader.Discard if available instead? - r.readFull(r.rdBuf[:n]) + if err == nil { + r.readFull(r.rdBuf[:n]) + } r.rdBuf = adjName[:0] // in case 2*n wasn't enough + + if DynlinkingGo() { + // These types are included in the symbol + // table when dynamically linking. To keep + // binary size down, we replace the names + // with SHA-1 prefixes. + // + // Keep the type.. prefix, which parts of the + // linker (like the DWARF generator) know means + // the symbol is not decodable. + // + // Leave type.runtime. symbols alone, because + // other parts of the linker manipulates them. + if strings.HasPrefix(s, "type.") && !strings.HasPrefix(s, "type.runtime.") { + hash := sha1.Sum([]byte(s)) + prefix := "type." + if s[5] == '.' { + prefix = "type.." + } + s = prefix + base64.StdEncoding.EncodeToString(hash[:6]) + } + } return s } adjName = append(adjName, origName[:i]...) diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index ff29ce2d70..991b9ef2cd 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -93,7 +93,7 @@ func pciterinit(ctxt *Link, it *Pciter, d *Pcdata) { it.value = -1 it.start = 1 it.done = 0 - it.pcscale = uint32(ctxt.Arch.Minlc) + it.pcscale = uint32(ctxt.Arch.MinLC) pciternext(it) } @@ -127,8 +127,7 @@ func addpctab(ftab *LSym, off int32, d *Pcdata) int32 { var start int32 if len(d.P) > 0 { start = int32(len(ftab.P)) - Symgrow(Ctxt, ftab, int64(start)+int64(len(d.P))) - copy(ftab.P[start:], d.P) + Addbytes(Ctxt, ftab, d.P) } return int32(setuint32(Ctxt, ftab, int64(off), uint32(start))) } @@ -148,27 +147,21 @@ func renumberfiles(ctxt *Link, files []*LSym, d *Pcdata) { for i := 0; i < len(files); i++ { f = files[i] if f.Type != obj.SFILEPATH { - ctxt.Nhistfile++ - f.Value = int64(ctxt.Nhistfile) + ctxt.Filesyms = append(ctxt.Filesyms, f) + f.Value = int64(len(ctxt.Filesyms)) f.Type = obj.SFILEPATH - f.Next = ctxt.Filesyms f.Name = expandGoroot(f.Name) - ctxt.Filesyms = f } } newval := int32(-1) var out Pcdata - - var dv int32 var it Pciter - var oldval int32 - var v uint32 - var val int32 for pciterinit(ctxt, &it, d); it.done == 0; pciternext(&it) { // value delta - oldval = it.value + oldval := it.value + var val int32 if oldval == -1 { val = -1 } else { @@ -178,9 +171,9 @@ func renumberfiles(ctxt *Link, files []*LSym, d *Pcdata) { val = int32(files[oldval].Value) } - dv = val - newval + dv := val - newval newval = val - v = (uint32(dv) << 1) ^ uint32(int32(dv>>31)) + v := (uint32(dv) << 1) ^ uint32(dv>>31) addvarint(&out, v) // pc delta @@ -205,7 +198,7 @@ func container(s *LSym) int { // pclntab initializes the pclntab symbol with // runtime function and file name information. -var pclntab_zpcln Pcln +var pclntab_zpcln FuncInfo // These variables are used to initialize runtime.firstmoduledata, see symtab.go:symtab. var pclntabNfunc int32 @@ -229,40 +222,34 @@ func pclntab() { nfunc := int32(0) // Find container symbols, mark them with SCONTAINER - for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next { - if Ctxt.Cursym.Outer != nil { - Ctxt.Cursym.Outer.Type |= obj.SCONTAINER + for _, s := range Ctxt.Textp { + if s.Outer != nil { + s.Outer.Type |= obj.SCONTAINER } } - for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next { - if container(Ctxt.Cursym) == 0 { + for _, s := range Ctxt.Textp { + if container(s) == 0 { nfunc++ } } pclntabNfunc = nfunc - Symgrow(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize)+4) + Symgrow(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize)+4) setuint32(Ctxt, ftab, 0, 0xfffffffb) - setuint8(Ctxt, ftab, 6, uint8(Thearch.Minlc)) - setuint8(Ctxt, ftab, 7, uint8(Thearch.Ptrsize)) - setuintxx(Ctxt, ftab, 8, uint64(nfunc), int64(Thearch.Ptrsize)) - pclntabPclntabOffset = int32(8 + Thearch.Ptrsize) + setuint8(Ctxt, ftab, 6, uint8(SysArch.MinLC)) + setuint8(Ctxt, ftab, 7, uint8(SysArch.PtrSize)) + setuintxx(Ctxt, ftab, 8, uint64(nfunc), int64(SysArch.PtrSize)) + pclntabPclntabOffset = int32(8 + SysArch.PtrSize) nfunc = 0 var last *LSym - var end int32 - var funcstart int32 - var i int32 - var it Pciter - var off int32 - var pcln *Pcln - for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next { + for _, Ctxt.Cursym = range Ctxt.Textp { last = Ctxt.Cursym if container(Ctxt.Cursym) != 0 { continue } - pcln = Ctxt.Cursym.Pcln + pcln := Ctxt.Cursym.FuncInfo if pcln == nil { pcln = &pclntab_zpcln } @@ -271,17 +258,17 @@ func pclntab() { pclntabFirstFunc = Ctxt.Cursym } - funcstart = int32(len(ftab.P)) - funcstart += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1) + funcstart := int32(len(ftab.P)) + funcstart += int32(-len(ftab.P)) & (int32(SysArch.PtrSize) - 1) - setaddr(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize), Ctxt.Cursym) - setuintxx(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint64(funcstart), int64(Thearch.Ptrsize)) + setaddr(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize), Ctxt.Cursym) + setuintxx(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize), uint64(funcstart), int64(SysArch.PtrSize)) // fixed size of struct, checked below - off = funcstart + off := funcstart - end = funcstart + int32(Thearch.Ptrsize) + 3*4 + 5*4 + int32(len(pcln.Pcdata))*4 + int32(len(pcln.Funcdata))*int32(Thearch.Ptrsize) - if len(pcln.Funcdata) > 0 && (end&int32(Thearch.Ptrsize-1) != 0) { + end := funcstart + int32(SysArch.PtrSize) + 3*4 + 5*4 + int32(len(pcln.Pcdata))*4 + int32(len(pcln.Funcdata))*int32(SysArch.PtrSize) + if len(pcln.Funcdata) > 0 && (end&int32(SysArch.PtrSize-1) != 0) { end += 4 } Symgrow(Ctxt, ftab, int64(end)) @@ -294,7 +281,11 @@ func pclntab() { // args int32 // TODO: Move into funcinfo. - off = int32(setuint32(Ctxt, ftab, int64(off), uint32(Ctxt.Cursym.Args))) + args := uint32(0) + if Ctxt.Cursym.FuncInfo != nil { + args = uint32(Ctxt.Cursym.FuncInfo.Args) + } + off = int32(setuint32(Ctxt, ftab, int64(off), args)) // frame int32 // This has been removed (it was never set quite correctly anyway). @@ -307,9 +298,10 @@ func pclntab() { renumberfiles(Ctxt, pcln.File, &pcln.Pcfile) if false { // Sanity check the new numbering + var it Pciter for pciterinit(Ctxt, &it, &pcln.Pcfile); it.done == 0; pciternext(&it) { - if it.value < 1 || it.value > Ctxt.Nhistfile { - Diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, Ctxt.Nhistfile) + if it.value < 1 || it.value > int32(len(Ctxt.Filesyms)) { + Diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, len(Ctxt.Filesyms)) errorexit() } } @@ -323,32 +315,32 @@ func pclntab() { off = addpctab(ftab, off, &pcln.Pcline) off = int32(setuint32(Ctxt, ftab, int64(off), uint32(len(pcln.Pcdata)))) off = int32(setuint32(Ctxt, ftab, int64(off), uint32(len(pcln.Funcdata)))) - for i = 0; i < int32(len(pcln.Pcdata)); i++ { + for i := 0; i < len(pcln.Pcdata); i++ { off = addpctab(ftab, off, &pcln.Pcdata[i]) } // funcdata, must be pointer-aligned and we're only int32-aligned. // Missing funcdata will be 0 (nil pointer). if len(pcln.Funcdata) > 0 { - if off&int32(Thearch.Ptrsize-1) != 0 { + if off&int32(SysArch.PtrSize-1) != 0 { off += 4 } - for i = 0; i < int32(len(pcln.Funcdata)); i++ { + for i := 0; i < len(pcln.Funcdata); i++ { if pcln.Funcdata[i] == nil { - setuintxx(Ctxt, ftab, int64(off)+int64(Thearch.Ptrsize)*int64(i), uint64(pcln.Funcdataoff[i]), int64(Thearch.Ptrsize)) + setuintxx(Ctxt, ftab, int64(off)+int64(SysArch.PtrSize)*int64(i), uint64(pcln.Funcdataoff[i]), int64(SysArch.PtrSize)) } else { // TODO: Dedup. funcdata_bytes += pcln.Funcdata[i].Size - setaddrplus(Ctxt, ftab, int64(off)+int64(Thearch.Ptrsize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i]) + setaddrplus(Ctxt, ftab, int64(off)+int64(SysArch.PtrSize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i]) } } - off += int32(len(pcln.Funcdata)) * int32(Thearch.Ptrsize) + off += int32(len(pcln.Funcdata)) * int32(SysArch.PtrSize) } if off != end { - Diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, len(pcln.Pcdata), len(pcln.Funcdata), Thearch.Ptrsize) + Diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, len(pcln.Pcdata), len(pcln.Funcdata), SysArch.PtrSize) errorexit() } @@ -357,25 +349,26 @@ func pclntab() { pclntabLastFunc = last // Final entry of table is just end pc. - setaddrplus(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize), last, last.Size) + setaddrplus(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize), last, last.Size) // Start file table. start := int32(len(ftab.P)) - start += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1) + start += int32(-len(ftab.P)) & (int32(SysArch.PtrSize) - 1) pclntabFiletabOffset = start - setuint32(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint32(start)) + setuint32(Ctxt, ftab, 8+int64(SysArch.PtrSize)+int64(nfunc)*2*int64(SysArch.PtrSize)+int64(SysArch.PtrSize), uint32(start)) - Symgrow(Ctxt, ftab, int64(start)+(int64(Ctxt.Nhistfile)+1)*4) - setuint32(Ctxt, ftab, int64(start), uint32(Ctxt.Nhistfile)) - for s := Ctxt.Filesyms; s != nil; s = s.Next { + Symgrow(Ctxt, ftab, int64(start)+(int64(len(Ctxt.Filesyms))+1)*4) + setuint32(Ctxt, ftab, int64(start), uint32(len(Ctxt.Filesyms))) + for i := len(Ctxt.Filesyms) - 1; i >= 0; i-- { + s := Ctxt.Filesyms[i] setuint32(Ctxt, ftab, int64(start)+s.Value*4, uint32(ftabaddstring(ftab, s.Name))) } ftab.Size = int64(len(ftab.P)) if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "%5.2f pclntab=%d bytes, funcdata total %d bytes\n", obj.Cputime(), int64(ftab.Size), int64(funcdata_bytes)) + fmt.Fprintf(Bso, "%5.2f pclntab=%d bytes, funcdata total %d bytes\n", obj.Cputime(), ftab.Size, funcdata_bytes) } } @@ -407,10 +400,9 @@ func findfunctab() { t.Attr |= AttrLocal // find min and max address - min := Ctxt.Textp.Value - + min := Ctxt.Textp[0].Value max := int64(0) - for s := Ctxt.Textp; s != nil; s = s.Next { + for _, s := range Ctxt.Textp { max = s.Value + s.Size } @@ -423,34 +415,34 @@ func findfunctab() { indexes[i] = NOIDX } idx := int32(0) - var e *LSym - var i int32 - var p int64 - var q int64 - for s := Ctxt.Textp; s != nil; s = s.Next { + for i, s := range Ctxt.Textp { if container(s) != 0 { continue } - p = s.Value - e = s.Next - for container(e) != 0 { - e = e.Next + p := s.Value + var e *LSym + i++ + if i < len(Ctxt.Textp) { + e = Ctxt.Textp[i] + } + for container(e) != 0 && i < len(Ctxt.Textp) { + e = Ctxt.Textp[i] + i++ } + q := max if e != nil { q = e.Value - } else { - q = max } //print("%d: [%lld %lld] %s\n", idx, p, q, s->name); for ; p < q; p += SUBBUCKETSIZE { - i = int32((p - min) / SUBBUCKETSIZE) + i = int((p - min) / SUBBUCKETSIZE) if indexes[i] > idx { indexes[i] = idx } } - i = int32((q - 1 - min) / SUBBUCKETSIZE) + i = int((q - 1 - min) / SUBBUCKETSIZE) if indexes[i] > idx { indexes[i] = idx } @@ -463,15 +455,13 @@ func findfunctab() { Symgrow(Ctxt, t, 4*int64(nbuckets)+int64(n)) // fill in table - var base int32 - var j int32 for i := int32(0); i < nbuckets; i++ { - base = indexes[i*SUBBUCKETS] + base := indexes[i*SUBBUCKETS] if base == NOIDX { Diag("hole in findfunctab") } setuint32(Ctxt, t, int64(i)*(4+SUBBUCKETS), uint32(base)) - for j = 0; j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ { + for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ { idx = indexes[i*SUBBUCKETS+j] if idx == NOIDX { Diag("hole in findfunctab") diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index 56698361d0..839aa6cca7 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -6,6 +6,7 @@ package ld import ( "cmd/internal/obj" + "cmd/internal/sys" "encoding/binary" "fmt" "os" @@ -419,9 +420,9 @@ func chksectseg(h *IMAGE_SECTION_HEADER, s *Segment) { func Peinit() { var l int - switch Thearch.Thechar { + switch SysArch.Family { // 64-bit architectures - case '6': + case sys.AMD64: pe64 = 1 l = binary.Size(&oh64) @@ -506,7 +507,7 @@ func initdynimport() *Dll { if err != nil { Diag("failed to parse stdcall decoration: %v", err) } - m.argsize *= Thearch.Ptrsize + m.argsize *= SysArch.PtrSize s.Extname = s.Extname[:i] } @@ -520,10 +521,10 @@ func initdynimport() *Dll { for d := dr; d != nil; d = d.next { for m = d.ms; m != nil; m = m.next { m.s.Type = obj.SDATA - Symgrow(Ctxt, m.s, int64(Thearch.Ptrsize)) + Symgrow(Ctxt, m.s, int64(SysArch.PtrSize)) dynName := m.s.Extname // only windows/386 requires stdcall decoration - if Thearch.Thechar == '8' && m.argsize >= 0 { + if SysArch.Family == sys.I386 && m.argsize >= 0 { dynName += fmt.Sprintf("@%d", m.argsize) } dynSym := Linklookup(Ctxt, dynName, 0) @@ -532,7 +533,7 @@ func initdynimport() *Dll { r := Addrel(m.s) r.Sym = dynSym r.Off = 0 - r.Siz = uint8(Thearch.Ptrsize) + r.Siz = uint8(SysArch.PtrSize) r.Type = obj.R_ADDR } } @@ -546,10 +547,10 @@ func initdynimport() *Dll { m.s.Sub = dynamic.Sub dynamic.Sub = m.s m.s.Value = dynamic.Size - dynamic.Size += int64(Thearch.Ptrsize) + dynamic.Size += int64(SysArch.PtrSize) } - dynamic.Size += int64(Thearch.Ptrsize) + dynamic.Size += int64(SysArch.PtrSize) } } @@ -763,7 +764,7 @@ func addexports() { // perelocsect relocates symbols from first in section sect, and returns // the total number of relocations emitted. -func perelocsect(sect *Section, first *LSym) int { +func perelocsect(sect *Section, syms []*LSym) int { // If main section has no bits, nothing to relocate. if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen { return 0 @@ -772,20 +773,18 @@ func perelocsect(sect *Section, first *LSym) int { relocs := 0 sect.Reloff = uint64(Cpos()) - var sym *LSym - for sym = first; sym != nil; sym = sym.Next { - if !sym.Attr.Reachable() { + for i, s := range syms { + if !s.Attr.Reachable() { continue } - if uint64(sym.Value) >= sect.Vaddr { + if uint64(s.Value) >= sect.Vaddr { + syms = syms[i:] break } } eaddr := int32(sect.Vaddr + sect.Length) - var r *Reloc - var ri int - for ; sym != nil; sym = sym.Next { + for _, sym := range syms { if !sym.Attr.Reachable() { continue } @@ -794,8 +793,8 @@ func perelocsect(sect *Section, first *LSym) int { } Ctxt.Cursym = sym - for ri = 0; ri < len(sym.R); ri++ { - r = &sym.R[ri] + for ri := 0; ri < len(sym.R); ri++ { + r := &sym.R[ri] if r.Done != 0 { continue } @@ -876,7 +875,7 @@ func peemitreloc(text, data, ctors *IMAGE_SECTION_HEADER) { ctors.NumberOfRelocations = 1 ctors.PointerToRelocations = uint32(Cpos()) sectoff := ctors.VirtualAddress - Lputl(uint32(sectoff)) + Lputl(sectoff) Lputl(uint32(dottext.Dynid)) switch obj.Getgoarch() { default: @@ -946,7 +945,7 @@ func writePESymTableRecords() int { } // only windows/386 requires underscore prefix on external symbols - if Thearch.Thechar == '8' && + if SysArch.Family == sys.I386 && Linkmode == LinkExternal && (s.Type != obj.SDYNIMPORT || s.Attr.CgoExport()) && s.Name == s.Extname && @@ -1002,7 +1001,7 @@ func writePESymTableRecords() int { for d := dr; d != nil; d = d.next { for m := d.ms; m != nil; m = m.next { s := m.s.R[0].Xsym - put(s, s.Name, 'U', 0, int64(Thearch.Ptrsize), 0, nil) + put(s, s.Name, 'U', 0, int64(SysArch.PtrSize), 0, nil) } } @@ -1042,7 +1041,7 @@ func addpesymtable() { // write COFF string table Lputl(uint32(len(strtbl)) + 4) for i := 0; i < len(strtbl); i++ { - Cput(uint8(strtbl[i])) + Cput(strtbl[i]) } if Linkmode != LinkExternal { strnput("", int(h.SizeOfRawData-uint32(size))) @@ -1129,12 +1128,12 @@ func addinitarray() (c *IMAGE_SECTION_HEADER) { } func Asmbpe() { - switch Thearch.Thechar { + switch SysArch.Family { default: - Exitf("unknown PE architecture: %v", Thearch.Thechar) - case '6': + Exitf("unknown PE architecture: %v", SysArch.Family) + case sys.AMD64: fh.Machine = IMAGE_FILE_MACHINE_AMD64 - case '8': + case sys.I386: fh.Machine = IMAGE_FILE_MACHINE_I386 } diff --git a/src/cmd/link/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go index f48b54efda..b64bb5deaf 100644 --- a/src/cmd/link/internal/ld/pobj.go +++ b/src/cmd/link/internal/ld/pobj.go @@ -31,7 +31,9 @@ package ld import ( + "bufio" "cmd/internal/obj" + "cmd/internal/sys" "flag" "fmt" "os" @@ -44,13 +46,12 @@ var ( ) func Ldmain() { - Ctxt = linknew(Thelinkarch) - Ctxt.Thechar = int32(Thearch.Thechar) - Ctxt.Thestring = Thestring + Bso = bufio.NewWriter(os.Stdout) + + Ctxt = linknew(SysArch) Ctxt.Diag = Diag - Ctxt.Bso = &Bso + Ctxt.Bso = Bso - Bso = *obj.Binitw(os.Stdout) Debug = [128]int{} nerrors = 0 outfile = "" @@ -70,7 +71,7 @@ func Ldmain() { } } - if Thearch.Thechar == '6' && obj.Getgoos() == "plan9" { + if SysArch.Family == sys.AMD64 && obj.Getgoos() == "plan9" { obj.Flagcount("8", "use 64-bit addresses in symbol table", &Debug['8']) } obj.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF", addbuildinfo) @@ -89,6 +90,7 @@ func Ldmain() { flag.Var(&Buildmode, "buildmode", "set build `mode`") obj.Flagcount("c", "dump call graph", &Debug['c']) obj.Flagcount("d", "disable dynamic executable", &Debug['d']) + flag.BoolVar(&flag_dumpdep, "dumpdep", false, "dump symbol dependency graph") obj.Flagstr("extar", "archive program for buildmode=c-archive", &extar) obj.Flagstr("extld", "use `linker` when linking in external mode", &extld) obj.Flagstr("extldflags", "pass `flags` to external linker", &extldflags) @@ -107,7 +109,7 @@ func Ldmain() { obj.Flagcount("race", "enable race detector", &flag_race) obj.Flagcount("s", "disable symbol table", &Debug['s']) var flagShared int - if Thearch.Thechar == '5' || Thearch.Thechar == '6' { + if SysArch.InFamily(sys.ARM, sys.AMD64) { obj.Flagcount("shared", "generate shared object (implies -linkmode external)", &flagShared) } obj.Flagstr("tmpdir", "use `directory` for temporary files", &tmpdir) @@ -122,7 +124,7 @@ func Ldmain() { obj.Flagparse(usage) startProfile() - Ctxt.Bso = &Bso + Ctxt.Bso = Bso Ctxt.Debugvlog = int32(Debug['v']) if flagShared != 0 { if Buildmode == BuildmodeUnset { @@ -163,7 +165,7 @@ func Ldmain() { } if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "HEADER = -H%d -T0x%x -D0x%x -R0x%x\n", HEADTYPE, uint64(INITTEXT), uint64(INITDAT), uint32(INITRND)) + fmt.Fprintf(Bso, "HEADER = -H%d -T0x%x -D0x%x -R0x%x\n", HEADTYPE, uint64(INITTEXT), uint64(INITDAT), uint32(INITRND)) } Bso.Flush() @@ -214,9 +216,9 @@ func Ldmain() { hostlink() archive() if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "%5.2f cpu time\n", obj.Cputime()) - fmt.Fprintf(&Bso, "%d symbols\n", len(Ctxt.Allsym)) - fmt.Fprintf(&Bso, "%d liveness data\n", liveness) + fmt.Fprintf(Bso, "%5.2f cpu time\n", obj.Cputime()) + fmt.Fprintf(Bso, "%d symbols\n", len(Ctxt.Allsym)) + fmt.Fprintf(Bso, "%d liveness data\n", liveness) } Bso.Flush() diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go index 3deb94644e..76fe7dab79 100644 --- a/src/cmd/link/internal/ld/sym.go +++ b/src/cmd/link/internal/ld/sym.go @@ -33,6 +33,7 @@ package ld import ( "cmd/internal/obj" + "cmd/internal/sys" "log" "strconv" ) @@ -55,7 +56,7 @@ var headers = []struct { {"windowsgui", obj.Hwindows}, } -func linknew(arch *LinkArch) *Link { +func linknew(arch *sys.Arch) *Link { ctxt := &Link{ Hash: []map[string]*LSym{ // preallocate about 2mb for hash of @@ -98,33 +99,33 @@ func linknew(arch *LinkArch) *Link { obj.Hdragonfly, obj.Hsolaris: if obj.Getgoos() == "android" { - switch ctxt.Arch.Thechar { - case '6': + switch ctxt.Arch.Family { + case sys.AMD64: // Android/amd64 constant - offset from 0(FS) to our TLS slot. // Explained in src/runtime/cgo/gcc_android_*.c ctxt.Tlsoffset = 0x1d0 - case '8': + case sys.I386: // Android/386 constant - offset from 0(GS) to our TLS slot. ctxt.Tlsoffset = 0xf8 default: - ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize + ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize } } else { - ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize + ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize } case obj.Hnacl: - switch ctxt.Arch.Thechar { + switch ctxt.Arch.Family { default: log.Fatalf("unknown thread-local storage offset for nacl/%s", ctxt.Arch.Name) - case '5': + case sys.ARM: ctxt.Tlsoffset = 0 - case '6': + case sys.AMD64: ctxt.Tlsoffset = 0 - case '8': + case sys.I386: ctxt.Tlsoffset = -8 } @@ -133,26 +134,26 @@ func linknew(arch *LinkArch) *Link { * Explained in src/runtime/cgo/gcc_darwin_*.c. */ case obj.Hdarwin: - switch ctxt.Arch.Thechar { + switch ctxt.Arch.Family { default: log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name) - case '5': + case sys.ARM: ctxt.Tlsoffset = 0 // dummy value, not needed - case '6': + case sys.AMD64: ctxt.Tlsoffset = 0x8a0 - case '7': + case sys.ARM64: ctxt.Tlsoffset = 0 // dummy value, not needed - case '8': + case sys.I386: ctxt.Tlsoffset = 0x468 } } // On arm, record goarm. - if ctxt.Arch.Thechar == '5' { + if ctxt.Arch.Family == sys.ARM { ctxt.Goarm = obj.Getgoarm() } diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index 3258bc1ff9..94a6d0ab29 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -32,6 +32,7 @@ package ld import ( "cmd/internal/obj" + "cmd/internal/sys" "fmt" "path/filepath" "strings" @@ -53,21 +54,14 @@ func putelfstr(s string) int { s = strings.Replace(s, "·", ".", -1) } - n := len(s) + 1 - for len(Elfstrdat)+n > cap(Elfstrdat) { - Elfstrdat = append(Elfstrdat[:cap(Elfstrdat)], 0)[:len(Elfstrdat)] - } - off := len(Elfstrdat) - Elfstrdat = Elfstrdat[:off+n] - copy(Elfstrdat[off:], s) - + Elfstrdat = append(Elfstrdat, s...) + Elfstrdat = append(Elfstrdat, 0) return off } func putelfsyment(off int, addr int64, size int64, info int, shndx int, other int) { - switch Thearch.Thechar { - case '0', '6', '7', '9', 'z': + if elf64 { Thearch.Lput(uint32(off)) Cput(uint8(info)) Cput(uint8(other)) @@ -75,8 +69,7 @@ func putelfsyment(off int, addr int64, size int64, info int, shndx int, other in Thearch.Vput(uint64(addr)) Thearch.Vput(uint64(size)) Symsize += ELF64SYMSIZE - - default: + } else { Thearch.Lput(uint32(off)) Thearch.Lput(uint32(addr)) Thearch.Lput(uint32(size)) @@ -162,7 +155,7 @@ func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *L if x.Type&obj.SHIDDEN != 0 { other = STV_HIDDEN } - if (Buildmode == BuildmodePIE || DynlinkingGo()) && Thearch.Thechar == '9' && type_ == STT_FUNC && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" { + if (Buildmode == BuildmodePIE || DynlinkingGo()) && SysArch.Family == sys.PPC64 && type_ == STT_FUNC && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" { // On ppc64 the top three bits of the st_other field indicate how // many instructions separate the global and local entry points. In // our case it is two instructions, indicated by the value 3. @@ -197,18 +190,6 @@ func putelfsectionsym(s *LSym, shndx int) { numelfsym++ } -func putelfsymshndx(sympos int64, shndx int) { - here := Cpos() - if elf64 { - Cseek(sympos + 6) - } else { - Cseek(sympos + 14) - } - - Thearch.Wput(uint16(shndx)) - Cseek(here) -} - func Asmelfsym() { // the first symbol entry is reserved putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0) @@ -217,7 +198,9 @@ func Asmelfsym() { // Some linkers will add a FILE sym if one is not present. // Avoid having the working directory inserted into the symbol table. - putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_FILE, SHN_ABS, 0) + // It is added with a name to avoid problems with external linking + // encountered on some versions of Solaris. See issue #14957. + putelfsyment(putelfstr("go.go"), 0, 0, STB_LOCAL<<4|STT_FILE, SHN_ABS, 0) numelfsym++ elfbind = STB_LOCAL @@ -243,7 +226,7 @@ func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ 'Z', 'm': l := 4 - if HEADTYPE == obj.Hplan9 && Thearch.Thechar == '6' && Debug['8'] == 0 { + if HEADTYPE == obj.Hplan9 && SysArch.Family == sys.AMD64 && Debug['8'] == 0 { Lputb(uint32(addr >> 32)) l = 8 } @@ -253,10 +236,10 @@ func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ var i int if t == 'z' || t == 'Z' { - Cput(uint8(s[0])) + Cput(s[0]) for i = 1; s[i] != 0 || s[i+1] != 0; i += 2 { - Cput(uint8(s[i])) - Cput(uint8(s[i+1])) + Cput(s[i]) + Cput(s[i+1]) } Cput(0) @@ -268,7 +251,7 @@ func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ s = s[1:] } for i = 0; i < len(s); i++ { - Cput(uint8(s[i])) + Cput(s[i]) } Cput(0) } @@ -346,6 +329,8 @@ func symtab() { xdefine("runtime.eitablink", obj.SRODATA, 0) xdefine("runtime.rodata", obj.SRODATA, 0) xdefine("runtime.erodata", obj.SRODATA, 0) + xdefine("runtime.types", obj.SRODATA, 0) + xdefine("runtime.etypes", obj.SRODATA, 0) xdefine("runtime.noptrdata", obj.SNOPTRDATA, 0) xdefine("runtime.enoptrdata", obj.SNOPTRDATA, 0) xdefine("runtime.data", obj.SDATA, 0) @@ -399,33 +384,19 @@ func symtab() { symtyperel = s } - s = Linklookup(Ctxt, "go.string.*", 0) - s.Type = obj.SGOSTRING - s.Attr |= AttrLocal - s.Size = 0 - s.Attr |= AttrReachable - symgostring := s - - s = Linklookup(Ctxt, "go.string.hdr.*", 0) - s.Type = obj.SGOSTRINGHDR - s.Attr |= AttrLocal - s.Size = 0 - s.Attr |= AttrReachable - symgostringhdr := s - - s = Linklookup(Ctxt, "go.func.*", 0) - s.Type = obj.SGOFUNC - s.Attr |= AttrLocal - s.Size = 0 - s.Attr |= AttrReachable - symgofunc := s - - s = Linklookup(Ctxt, "runtime.gcbits.*", 0) - s.Type = obj.SGCBITS - s.Attr |= AttrLocal - s.Size = 0 - s.Attr |= AttrReachable - symgcbits := s + groupSym := func(name string, t int16) *LSym { + s := Linklookup(Ctxt, name, 0) + s.Type = t + s.Size = 0 + s.Attr |= AttrLocal | AttrReachable + return s + } + var ( + symgostring = groupSym("go.string.*", obj.SGOSTRING) + symgostringhdr = groupSym("go.string.hdr.*", obj.SGOSTRINGHDR) + symgofunc = groupSym("go.func.*", obj.SGOFUNC) + symgcbits = groupSym("runtime.gcbits.*", obj.SGCBITS) + ) symtypelink := Linklookup(Ctxt, "runtime.typelink", 0) symtypelink.Type = obj.STYPELINK @@ -451,34 +422,37 @@ func symtab() { continue } - if strings.HasPrefix(s.Name, "type.") { + switch { + case strings.HasPrefix(s.Name, "type."): if !DynlinkingGo() { s.Attr |= AttrHidden } - if UseRelro() && len(s.R) > 0 { + if UseRelro() { s.Type = obj.STYPERELRO s.Outer = symtyperel } else { s.Type = obj.STYPE s.Outer = symtype } - } - if strings.HasPrefix(s.Name, "go.typelink.") { + case strings.HasPrefix(s.Name, "go.importpath.") && UseRelro(): + // Keep go.importpath symbols in the same section as types and + // names, as they can be referred to by a section offset. + s.Type = obj.STYPERELRO + + case strings.HasPrefix(s.Name, "go.typelink."): ntypelinks++ s.Type = obj.STYPELINK s.Attr |= AttrHidden s.Outer = symtypelink - } - if strings.HasPrefix(s.Name, "go.itablink.") { + case strings.HasPrefix(s.Name, "go.itablink."): nitablinks++ s.Type = obj.SITABLINK s.Attr |= AttrHidden s.Outer = symitablink - } - if strings.HasPrefix(s.Name, "go.string.") { + case strings.HasPrefix(s.Name, "go.string."): s.Type = obj.SGOSTRING s.Attr |= AttrHidden s.Outer = symgostring @@ -486,21 +460,18 @@ func symtab() { s.Type = obj.SGOSTRINGHDR s.Outer = symgostringhdr } - } - if strings.HasPrefix(s.Name, "runtime.gcbits.") { + case strings.HasPrefix(s.Name, "runtime.gcbits."): s.Type = obj.SGCBITS s.Attr |= AttrHidden s.Outer = symgcbits - } - if strings.HasPrefix(s.Name, "go.func.") { + case strings.HasPrefix(s.Name, "go.func."): s.Type = obj.SGOFUNC s.Attr |= AttrHidden s.Outer = symgofunc - } - if strings.HasPrefix(s.Name, "gcargs.") || strings.HasPrefix(s.Name, "gclocals.") || strings.HasPrefix(s.Name, "gclocals·") { + case strings.HasPrefix(s.Name, "gcargs."), strings.HasPrefix(s.Name, "gclocals."), strings.HasPrefix(s.Name, "gclocals·"): s.Type = obj.SGOFUNC s.Attr |= AttrHidden s.Outer = symgofunc @@ -533,8 +504,8 @@ func symtab() { adduint(Ctxt, moduledata, uint64(pclntabNfunc+1)) // The filetab slice Addaddrplus(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0), int64(pclntabFiletabOffset)) - adduint(Ctxt, moduledata, uint64(Ctxt.Nhistfile)+1) - adduint(Ctxt, moduledata, uint64(Ctxt.Nhistfile)+1) + adduint(Ctxt, moduledata, uint64(len(Ctxt.Filesyms))+1) + adduint(Ctxt, moduledata, uint64(len(Ctxt.Filesyms))+1) // findfunctab Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.findfunctab", 0)) // minpc, maxpc @@ -554,6 +525,8 @@ func symtab() { Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.end", 0)) Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcdata", 0)) Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcbss", 0)) + Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.types", 0)) + Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.etypes", 0)) // The typelinks slice Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0)) adduint(Ctxt, moduledata, uint64(ntypelinks)) diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go index 8249c54e45..785002b02c 100644 --- a/src/cmd/link/internal/mips64/asm.go +++ b/src/cmd/link/internal/mips64/asm.go @@ -32,6 +32,7 @@ package mips64 import ( "cmd/internal/obj" + "cmd/internal/sys" "cmd/link/internal/ld" "encoding/binary" "fmt" @@ -40,10 +41,6 @@ import ( func gentext() {} -func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) { - log.Fatalf("adddynrela not implemented") -} - func adddynrel(s *ld.LSym, r *ld.Reloc) { log.Fatalf("adddynrel not implemented") } @@ -82,8 +79,8 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { // the first instruction is always at the lower address, this is endian neutral; // but note that o1 and o2 should still use the target endian. - o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off:]) - o2 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4:]) + o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:]) + o2 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off+4:]) o1 = o1&0xffff0000 | uint32(t>>16)&0xffff o2 = o2&0xffff0000 | uint32(t)&0xffff @@ -99,7 +96,7 @@ func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int { obj.R_JMPMIPS: // Low 26 bits = (S + A) >> 2 t := ld.Symaddr(r.Sym) + r.Add - o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off:]) + o1 := ld.SysArch.ByteOrder.Uint32(s.P[r.Off:]) *val = int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000) return 0 } @@ -113,7 +110,7 @@ func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 { func asmb() { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime()) } ld.Bso.Flush() @@ -131,7 +128,7 @@ func asmb() { if ld.Segrodata.Filelen > 0 { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) } ld.Bso.Flush() @@ -140,13 +137,16 @@ func asmb() { } if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime()) } ld.Bso.Flush() ld.Cseek(int64(ld.Segdata.Fileoff)) ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) + ld.Cseek(int64(ld.Segdwarf.Fileoff)) + ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) + /* output symbol table */ ld.Symsize = 0 @@ -155,13 +155,13 @@ func asmb() { if ld.Debug['s'] == 0 { // TODO: rationalize if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime()) } ld.Bso.Flush() switch ld.HEADTYPE { default: if ld.Iself { - symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) + symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND))) } @@ -174,17 +174,12 @@ func asmb() { default: if ld.Iself { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime()) } ld.Asmelfsym() ld.Cflush() ld.Cwrite(ld.Elfstrdat) - if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) - } - ld.Dwarfemitdebugsections() - if ld.Linkmode == ld.LinkExternal { ld.Elfemitreloc() } @@ -198,7 +193,7 @@ func asmb() { if sym != nil { ld.Lcsize = int32(len(sym.P)) for i := 0; int32(i) < ld.Lcsize; i++ { - ld.Cput(uint8(sym.P[i])) + ld.Cput(sym.P[i]) } ld.Cflush() @@ -208,7 +203,7 @@ func asmb() { ld.Ctxt.Cursym = nil if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime()) } ld.Bso.Flush() ld.Cseek(0) @@ -216,10 +211,10 @@ func asmb() { default: case obj.Hplan9: /* plan 9 */ magic := uint32(4*18*18 + 7) - if ld.Thestring == "mips64le" { + if ld.SysArch == sys.ArchMIPS64LE { magic = uint32(4*26*26 + 7) } - ld.Thearch.Lput(uint32(magic)) /* magic */ + ld.Thearch.Lput(magic) /* magic */ ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */ ld.Thearch.Lput(uint32(ld.Segdata.Filelen)) ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen)) diff --git a/src/cmd/link/internal/mips64/l.go b/src/cmd/link/internal/mips64/l.go index 003ee5ce71..f4191e69ab 100644 --- a/src/cmd/link/internal/mips64/l.go +++ b/src/cmd/link/internal/mips64/l.go @@ -62,11 +62,9 @@ package mips64 // THE SOFTWARE. const ( - thechar = '0' MaxAlign = 32 // max data alignment MinAlign = 1 // min data alignment FuncAlign = 8 - MINLC = 4 ) /* Used by ../internal/ld/dwarf.go */ diff --git a/src/cmd/link/internal/mips64/obj.go b/src/cmd/link/internal/mips64/obj.go index 57a1b2ab14..87bb3a079b 100644 --- a/src/cmd/link/internal/mips64/obj.go +++ b/src/cmd/link/internal/mips64/obj.go @@ -32,6 +32,7 @@ package mips64 import ( "cmd/internal/obj" + "cmd/internal/sys" "cmd/link/internal/ld" "fmt" "log" @@ -45,21 +46,15 @@ func Main() { } func linkarchinit() { - ld.Thestring = obj.Getgoarch() - if ld.Thestring == "mips64le" { - ld.Thelinkarch = &ld.Linkmips64le + if obj.Getgoarch() == "mips64le" { + ld.SysArch = sys.ArchMIPS64LE } else { - ld.Thelinkarch = &ld.Linkmips64 + ld.SysArch = sys.ArchMIPS64 } - ld.Thearch.Thechar = thechar - ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize - ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize - ld.Thearch.Regsize = ld.Thelinkarch.Regsize ld.Thearch.Funcalign = FuncAlign ld.Thearch.Maxalign = MaxAlign ld.Thearch.Minalign = MinAlign - ld.Thearch.Minlc = MINLC ld.Thearch.Dwarfregsp = DWARFREGSP ld.Thearch.Dwarfreglr = DWARFREGLR @@ -72,7 +67,7 @@ func linkarchinit() { ld.Thearch.Elfsetupplt = elfsetupplt ld.Thearch.Gentext = gentext ld.Thearch.Machoreloc1 = machoreloc1 - if ld.Thelinkarch == &ld.Linkmips64le { + if ld.SysArch == sys.ArchMIPS64LE { ld.Thearch.Lput = ld.Lputl ld.Thearch.Wput = ld.Wputl ld.Thearch.Vput = ld.Vputl diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go index ae69799abf..dbf5fac0de 100644 --- a/src/cmd/link/internal/ppc64/asm.go +++ b/src/cmd/link/internal/ppc64/asm.go @@ -39,14 +39,6 @@ import ( ) func genplt() { - var s *ld.LSym - var stub *ld.LSym - var pprevtextp **ld.LSym - var r *ld.Reloc - var n string - var o1 uint32 - var i int - // The ppc64 ABI PLT has similar concepts to other // architectures, but is laid out quite differently. When we // see an R_PPC64_REL24 relocation to a dynamic symbol @@ -95,11 +87,9 @@ func genplt() { // // This assumes "case 1" from the ABI, where the caller needs // us to save and restore the TOC pointer. - pprevtextp = &ld.Ctxt.Textp - - for s = *pprevtextp; s != nil; pprevtextp, s = &s.Next, s.Next { - for i = range s.R { - r = &s.R[i] + for _, s := range ld.Ctxt.Textp { + for i := range s.R { + r := &s.R[i] if r.Type != 256+ld.R_PPC64_REL24 || r.Sym.Type != obj.SDYNIMPORT { continue } @@ -109,24 +99,16 @@ func genplt() { addpltsym(ld.Ctxt, r.Sym) // Generate call stub - n = fmt.Sprintf("%s.%s", s.Name, r.Sym.Name) + n := fmt.Sprintf("%s.%s", s.Name, r.Sym.Name) - stub = ld.Linklookup(ld.Ctxt, n, 0) + stub := ld.Linklookup(ld.Ctxt, n, 0) if s.Attr.Reachable() { stub.Attr |= ld.AttrReachable } if stub.Size == 0 { // Need outer to resolve .TOC. stub.Outer = s - - // Link in to textp before s (we could - // do it after, but would have to skip - // the subsymbols) - *pprevtextp = stub - - stub.Next = s - pprevtextp = &stub.Next - + ld.Ctxt.Textp = append(ld.Ctxt.Textp, stub) gencallstub(1, stub, r.Sym) } @@ -135,11 +117,10 @@ func genplt() { // Restore TOC after bl. The compiler put a // nop here for us to overwrite. - o1 = 0xe8410018 // ld r2,24(r1) + const o1 = 0xe8410018 // ld r2,24(r1) ld.Ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off+4:], o1) } } - } func genaddmoduledata() { @@ -195,13 +176,7 @@ func genaddmoduledata() { // blr o(0x4e800020) - if ld.Ctxt.Etextp != nil { - ld.Ctxt.Etextp.Next = initfunc - } else { - ld.Ctxt.Textp = initfunc - } - ld.Ctxt.Etextp = initfunc - + ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc) initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0) initarray_entry.Attr |= ld.AttrReachable initarray_entry.Attr |= ld.AttrLocal @@ -265,10 +240,6 @@ func gencallstub(abicase int, stub *ld.LSym, targ *ld.LSym) { ld.Adduint32(ld.Ctxt, stub, 0x4e800420) // bctr } -func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) { - log.Fatalf("adddynrela not implemented") -} - func adddynrel(s *ld.LSym, r *ld.Reloc) { targ := r.Sym ld.Ctxt.Cursym = s @@ -834,7 +805,7 @@ func ensureglinkresolver() *ld.LSym { func asmb() { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime()) } ld.Bso.Flush() @@ -852,7 +823,7 @@ func asmb() { if ld.Segrodata.Filelen > 0 { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) } ld.Bso.Flush() @@ -861,13 +832,16 @@ func asmb() { } if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime()) } ld.Bso.Flush() ld.Cseek(int64(ld.Segdata.Fileoff)) ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) + ld.Cseek(int64(ld.Segdwarf.Fileoff)) + ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) + /* output symbol table */ ld.Symsize = 0 @@ -876,13 +850,13 @@ func asmb() { if ld.Debug['s'] == 0 { // TODO: rationalize if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime()) } ld.Bso.Flush() switch ld.HEADTYPE { default: if ld.Iself { - symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) + symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND))) } @@ -895,17 +869,12 @@ func asmb() { default: if ld.Iself { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime()) } ld.Asmelfsym() ld.Cflush() ld.Cwrite(ld.Elfstrdat) - if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) - } - ld.Dwarfemitdebugsections() - if ld.Linkmode == ld.LinkExternal { ld.Elfemitreloc() } @@ -919,7 +888,7 @@ func asmb() { if sym != nil { ld.Lcsize = int32(len(sym.P)) for i := 0; int32(i) < ld.Lcsize; i++ { - ld.Cput(uint8(sym.P[i])) + ld.Cput(sym.P[i]) } ld.Cflush() @@ -929,7 +898,7 @@ func asmb() { ld.Ctxt.Cursym = nil if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime()) } ld.Bso.Flush() ld.Cseek(0) diff --git a/src/cmd/link/internal/ppc64/l.go b/src/cmd/link/internal/ppc64/l.go index 622d6bb12e..a720993fbc 100644 --- a/src/cmd/link/internal/ppc64/l.go +++ b/src/cmd/link/internal/ppc64/l.go @@ -62,11 +62,9 @@ package ppc64 // THE SOFTWARE. const ( - thechar = '9' MaxAlign = 32 // max data alignment MinAlign = 1 // min data alignment FuncAlign = 8 - MINLC = 4 ) /* Used by ../internal/ld/dwarf.go */ diff --git a/src/cmd/link/internal/ppc64/obj.go b/src/cmd/link/internal/ppc64/obj.go index 539ab1ac02..a540ab85b5 100644 --- a/src/cmd/link/internal/ppc64/obj.go +++ b/src/cmd/link/internal/ppc64/obj.go @@ -32,6 +32,7 @@ package ppc64 import ( "cmd/internal/obj" + "cmd/internal/sys" "cmd/link/internal/ld" "fmt" "log" @@ -45,21 +46,15 @@ func Main() { } func linkarchinit() { - ld.Thestring = obj.Getgoarch() - if ld.Thestring == "ppc64le" { - ld.Thelinkarch = &ld.Linkppc64le + if obj.Getgoarch() == "ppc64le" { + ld.SysArch = sys.ArchPPC64LE } else { - ld.Thelinkarch = &ld.Linkppc64 + ld.SysArch = sys.ArchPPC64 } - ld.Thearch.Thechar = thechar - ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize - ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize - ld.Thearch.Regsize = ld.Thelinkarch.Regsize ld.Thearch.Funcalign = FuncAlign ld.Thearch.Maxalign = MaxAlign ld.Thearch.Minalign = MinAlign - ld.Thearch.Minlc = MINLC ld.Thearch.Dwarfregsp = DWARFREGSP ld.Thearch.Dwarfreglr = DWARFREGLR @@ -72,7 +67,7 @@ func linkarchinit() { ld.Thearch.Elfsetupplt = elfsetupplt ld.Thearch.Gentext = gentext ld.Thearch.Machoreloc1 = machoreloc1 - if ld.Thelinkarch == &ld.Linkppc64le { + if ld.SysArch == sys.ArchPPC64LE { ld.Thearch.Lput = ld.Lputl ld.Thearch.Wput = ld.Wputl ld.Thearch.Vput = ld.Vputl @@ -150,7 +145,7 @@ func archinit() { } case obj.Hlinux: /* ppc64 elf */ - if ld.Thestring == "ppc64" { + if ld.SysArch == sys.ArchPPC64 { ld.Debug['d'] = 1 // TODO(austin): ELF ABI v1 not supported yet } ld.Elfinit() diff --git a/src/cmd/link/internal/s390x/asm.go b/src/cmd/link/internal/s390x/asm.go index 75a8206174..7c2e3358ff 100644 --- a/src/cmd/link/internal/s390x/asm.go +++ b/src/cmd/link/internal/s390x/asm.go @@ -90,12 +90,7 @@ func gentext() { // undef (for debugging) ld.Adduint32(ld.Ctxt, initfunc, 0) - if ld.Ctxt.Etextp != nil { - ld.Ctxt.Etextp.Next = initfunc - } else { - ld.Ctxt.Textp = initfunc - } - ld.Ctxt.Etextp = initfunc + ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc) initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0) initarray_entry.Attr |= ld.AttrLocal initarray_entry.Attr |= ld.AttrReachable @@ -505,7 +500,7 @@ func addgotsym(s *ld.LSym) { func asmb() { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime()) } ld.Bso.Flush() @@ -523,7 +518,7 @@ func asmb() { if ld.Segrodata.Filelen > 0 { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) } ld.Bso.Flush() @@ -532,13 +527,16 @@ func asmb() { } if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime()) } ld.Bso.Flush() ld.Cseek(int64(ld.Segdata.Fileoff)) ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) + ld.Cseek(int64(ld.Segdwarf.Fileoff)) + ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) + /* output symbol table */ ld.Symsize = 0 @@ -549,24 +547,23 @@ func asmb() { ld.Diag("unsupported executable format") } if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime()) } ld.Bso.Flush() - symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) + symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND))) ld.Cseek(int64(symo)) if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime()) } ld.Asmelfsym() ld.Cflush() ld.Cwrite(ld.Elfstrdat) if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime()) } - ld.Dwarfemitdebugsections() if ld.Linkmode == ld.LinkExternal { ld.Elfemitreloc() @@ -575,7 +572,7 @@ func asmb() { ld.Ctxt.Cursym = nil if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f header\n", obj.Cputime()) } ld.Bso.Flush() ld.Cseek(0) diff --git a/src/cmd/link/internal/s390x/l.go b/src/cmd/link/internal/s390x/l.go index 839a9849c8..42cf15ee85 100644 --- a/src/cmd/link/internal/s390x/l.go +++ b/src/cmd/link/internal/s390x/l.go @@ -62,14 +62,9 @@ package s390x // THE SOFTWARE. const ( - thechar = 'z' - PtrSize = 8 - IntSize = 8 - RegSize = 8 MaxAlign = 32 // max data alignment MinAlign = 2 // min data alignment FuncAlign = 16 - MINLC = 2 ) /* Used by ../internal/ld/dwarf.go */ diff --git a/src/cmd/link/internal/s390x/obj.go b/src/cmd/link/internal/s390x/obj.go index ef88d22bbd..fdb9898181 100644 --- a/src/cmd/link/internal/s390x/obj.go +++ b/src/cmd/link/internal/s390x/obj.go @@ -32,6 +32,7 @@ package s390x import ( "cmd/internal/obj" + "cmd/internal/sys" "cmd/link/internal/ld" "fmt" ) @@ -44,17 +45,11 @@ func Main() { } func linkarchinit() { - ld.Thestring = obj.Getgoarch() - ld.Thelinkarch = &ld.Links390x + ld.SysArch = sys.ArchS390X - ld.Thearch.Thechar = thechar - ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize - ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize - ld.Thearch.Regsize = ld.Thelinkarch.Regsize ld.Thearch.Funcalign = FuncAlign ld.Thearch.Maxalign = MaxAlign ld.Thearch.Minalign = MinAlign - ld.Thearch.Minlc = MINLC ld.Thearch.Dwarfregsp = DWARFREGSP ld.Thearch.Dwarfreglr = DWARFREGLR diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go index 97fccf3ee6..4a55b535ac 100644 --- a/src/cmd/link/internal/x86/asm.go +++ b/src/cmd/link/internal/x86/asm.go @@ -69,12 +69,7 @@ func gentext() { // c3 ret o(0xc3) - if ld.Ctxt.Etextp != nil { - ld.Ctxt.Etextp.Next = thunkfunc - } else { - ld.Ctxt.Textp = thunkfunc - } - ld.Ctxt.Etextp = thunkfunc + ld.Ctxt.Textp = append(ld.Ctxt.Textp, thunkfunc) addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0) if addmoduledata.Type == obj.STEXT { @@ -130,8 +125,7 @@ func gentext() { o(0xc3) - ld.Ctxt.Etextp.Next = initfunc - ld.Ctxt.Etextp = initfunc + ld.Ctxt.Textp = append(ld.Ctxt.Textp, initfunc) initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0) initarray_entry.Attr |= ld.AttrReachable initarray_entry.Attr |= ld.AttrLocal @@ -139,10 +133,6 @@ func gentext() { ld.Addaddr(ld.Ctxt, initarray_entry, initfunc) } -func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) { - log.Fatalf("adddynrela not implemented") -} - func adddynrel(s *ld.LSym, r *ld.Reloc) { targ := r.Sym ld.Ctxt.Cursym = s @@ -292,7 +282,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { return } - if ld.HEADTYPE == obj.Hdarwin && s.Size == PtrSize && r.Off == 0 { + if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.SysArch.PtrSize) && r.Off == 0 { // Mach-O relocations are a royal pain to lay out. // They use a compact stateful bytecode representation // that is too much bother to deal with. @@ -317,7 +307,7 @@ func adddynrel(s *ld.LSym, r *ld.Reloc) { return } - if ld.HEADTYPE == obj.Hwindows && s.Size == PtrSize { + if ld.HEADTYPE == obj.Hwindows && s.Size == int64(ld.SysArch.PtrSize) { // nothing to do, the relocation will be laid out in pereloc1 return } @@ -609,7 +599,7 @@ func addgotsym(ctxt *ld.Link, s *ld.LSym) { func asmb() { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f asmb\n", obj.Cputime()) } ld.Bso.Flush() @@ -627,7 +617,7 @@ func asmb() { if ld.Segrodata.Filelen > 0 { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f rodatblk\n", obj.Cputime()) } ld.Bso.Flush() @@ -636,26 +626,18 @@ func asmb() { } if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f datblk\n", obj.Cputime()) } ld.Bso.Flush() ld.Cseek(int64(ld.Segdata.Fileoff)) ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen)) + ld.Cseek(int64(ld.Segdwarf.Fileoff)) + ld.Dwarfblk(int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen)) + machlink := uint32(0) if ld.HEADTYPE == obj.Hdarwin { - if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) - } - - dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))) - ld.Cseek(int64(dwarfoff)) - - ld.Segdwarf.Fileoff = uint64(ld.Cpos()) - ld.Dwarfemitdebugsections() - ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff - machlink = uint32(ld.Domacholink()) } @@ -666,13 +648,13 @@ func asmb() { if ld.Debug['s'] == 0 { // TODO: rationalize if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f sym\n", obj.Cputime()) } ld.Bso.Flush() switch ld.HEADTYPE { default: if ld.Iself { - symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) + symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND))) } @@ -683,7 +665,7 @@ func asmb() { symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink)) case obj.Hwindows: - symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen) + symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN)) } @@ -692,17 +674,12 @@ func asmb() { default: if ld.Iself { if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f elfsym\n", obj.Cputime()) } ld.Asmelfsym() ld.Cflush() ld.Cwrite(ld.Elfstrdat) - if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) - } - ld.Dwarfemitdebugsections() - if ld.Linkmode == ld.LinkExternal { ld.Elfemitreloc() } @@ -716,7 +693,7 @@ func asmb() { if sym != nil { ld.Lcsize = int32(len(sym.P)) for i := 0; int32(i) < ld.Lcsize; i++ { - ld.Cput(uint8(sym.P[i])) + ld.Cput(sym.P[i]) } ld.Cflush() @@ -724,9 +701,8 @@ func asmb() { case obj.Hwindows: if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f dwarf\n", obj.Cputime()) } - ld.Dwarfemitdebugsections() case obj.Hdarwin: if ld.Linkmode == ld.LinkExternal { @@ -736,7 +712,7 @@ func asmb() { } if ld.Debug['v'] != 0 { - fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime()) + fmt.Fprintf(ld.Bso, "%5.2f headr\n", obj.Cputime()) } ld.Bso.Flush() ld.Cseek(0) diff --git a/src/cmd/link/internal/x86/l.go b/src/cmd/link/internal/x86/l.go index 068fed9c8d..2043f9bb4e 100644 --- a/src/cmd/link/internal/x86/l.go +++ b/src/cmd/link/internal/x86/l.go @@ -31,12 +31,9 @@ package x86 const ( - thechar = '8' - PtrSize = 4 MaxAlign = 32 // max data alignment MinAlign = 1 // min data alignment FuncAlign = 16 - MINLC = 1 ) /* Used by ../internal/ld/dwarf.go */ diff --git a/src/cmd/link/internal/x86/obj.go b/src/cmd/link/internal/x86/obj.go index 4380c41ebb..574c0dad2d 100644 --- a/src/cmd/link/internal/x86/obj.go +++ b/src/cmd/link/internal/x86/obj.go @@ -32,6 +32,7 @@ package x86 import ( "cmd/internal/obj" + "cmd/internal/sys" "cmd/link/internal/ld" "fmt" "log" @@ -45,17 +46,11 @@ func Main() { } func linkarchinit() { - ld.Thestring = "386" - ld.Thelinkarch = &ld.Link386 + ld.SysArch = sys.Arch386 - ld.Thearch.Thechar = thechar - ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize - ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize - ld.Thearch.Regsize = ld.Thelinkarch.Regsize ld.Thearch.Funcalign = FuncAlign ld.Thearch.Maxalign = MaxAlign ld.Thearch.Minalign = MinAlign - ld.Thearch.Minlc = MINLC ld.Thearch.Dwarfregsp = DWARFREGSP ld.Thearch.Dwarfreglr = DWARFREGLR |
