diff options
Diffstat (limited to 'src/cmd/link')
45 files changed, 2240 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 diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go new file mode 100644 index 0000000000..4ef184518e --- /dev/null +++ b/src/cmd/link/link_test.go @@ -0,0 +1,30 @@ +package main + +import "testing" + +var AuthorPaidByTheColumnInch struct { + fog int ` + London. Michaelmas term lately over, and the Lord Chancellor sitting in Lincoln’s Inn Hall. Implacable November weather. As much mud in the streets as if the waters had but newly retired from the face of the earth, and it would not be wonderful to meet a Megalosaurus, forty feet long or so, waddling like an elephantine lizard up Holborn Hill. Smoke lowering down from chimney-pots, making a soft black drizzle, with flakes of soot in it as big as full-grown snowflakes—gone into mourning, one might imagine, for the death of the sun. Dogs, undistinguishable in mire. Horses, scarcely better; splashed to their very blinkers. Foot passengers, jostling one another’s umbrellas in a general infection of ill temper, and losing their foot-hold at street-corners, where tens of thousands of other foot passengers have been slipping and sliding since the day broke (if this day ever broke), adding new deposits to the crust upon crust of mud, sticking at those points tenaciously to the pavement, and accumulating at compound interest. + + Fog everywhere. Fog up the river, where it flows among green aits and meadows; fog down the river, where it rolls defiled among the tiers of shipping and the waterside pollutions of a great (and dirty) city. Fog on the Essex marshes, fog on the Kentish heights. Fog creeping into the cabooses of collier-brigs; fog lying out on the yards and hovering in the rigging of great ships; fog drooping on the gunwales of barges and small boats. Fog in the eyes and throats of ancient Greenwich pensioners, wheezing by the firesides of their wards; fog in the stem and bowl of the afternoon pipe of the wrathful skipper, down in his close cabin; fog cruelly pinching the toes and fingers of his shivering little ‘prentice boy on deck. Chance people on the bridges peeping over the parapets into a nether sky of fog, with fog all round them, as if they were up in a balloon and hanging in the misty clouds. + + Gas looming through the fog in divers places in the streets, much as the sun may, from the spongey fields, be seen to loom by husbandman and ploughboy. Most of the shops lighted two hours before their time—as the gas seems to know, for it has a haggard and unwilling look. + + The raw afternoon is rawest, and the dense fog is densest, and the muddy streets are muddiest near that leaden-headed old obstruction, appropriate ornament for the threshold of a leaden-headed old corporation, Temple Bar. And hard by Temple Bar, in Lincoln’s Inn Hall, at the very heart of the fog, sits the Lord High Chancellor in his High Court of Chancery.` + + wind int ` + It was grand to see how the wind awoke, and bent the trees, and drove the rain before it like a cloud of smoke; and to hear the solemn thunder, and to see the lightning; and while thinking with awe of the tremendous powers by which our little lives are encompassed, to consider how beneficent they are, and how upon the smallest flower and leaf there was already a freshness poured from all this seeming rage, which seemed to make creation new again.` + + jarndyce int ` + Jarndyce and Jarndyce drones on. This scarecrow of a suit has, over the course of time, become so complicated, that no man alive knows what it means. The parties to it understand it least; but it has been observed that no two Chancery lawyers can talk about it for five minutes, without coming to a total disagreement as to all the premises. Innumerable children have been born into the cause; innumerable young people have married into it; innumerable old people have died out of it. Scores of persons have deliriously found themselves made parties in Jarndyce and Jarndyce, without knowing how or why; whole families have inherited legendary hatreds with the suit. The little plaintiff or defendant, who was promised a new rocking-horse when Jarndyce and Jarndyce should be settled, has grown up, possessed himself of a real horse, and trotted away into the other world. Fair wards of court have faded into mothers and grandmothers; a long procession of Chancellors has come in and gone out; the legion of bills in the suit have been transformed into mere bills of mortality; there are not three Jarndyces left upon the earth perhaps, since old Tom Jarndyce in despair blew his brains out at a coffee-house in Chancery Lane; but Jarndyce and Jarndyce still drags its dreary length before the Court, perennially hopeless.` + + principle int ` + The one great principle of the English law is, to make business for itself. There is no other principle distinctly, certainly, and consistently maintained through all its narrow turnings. Viewed by this light it becomes a coherent scheme, and not the monstrous maze the laity are apt to think it. Let them but once clearly perceive that its grand principle is to make business for itself at their expense, and surely they will cease to grumble.` +} + +func TestLargeSymName(t *testing.T) { + // The compiler generates a symbol name using the string form of the + // type. This tests that the linker can read symbol names larger than + // the bufio buffer. Issue #15104. + _ = AuthorPaidByTheColumnInch +} diff --git a/src/cmd/link/main.go b/src/cmd/link/main.go index e52b718699..f92e02eac3 100644 --- a/src/cmd/link/main.go +++ b/src/cmd/link/main.go @@ -11,6 +11,7 @@ import ( "cmd/link/internal/arm64" "cmd/link/internal/mips64" "cmd/link/internal/ppc64" + "cmd/link/internal/s390x" "cmd/link/internal/x86" "fmt" "os" @@ -33,5 +34,7 @@ func main() { mips64.Main() case "ppc64", "ppc64le": ppc64.Main() + case "s390x": + s390x.Main() } } |
