From ec3c5b9d178ee373a41e46f6074c8729cfd11084 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 5 Apr 2016 23:01:10 -0700 Subject: cmd/link: eliminate a bunch of open coded elf64/rela switches We already have variables to track whether the target platform is 64-bit vs 32-bit or RELA vs REL, so no point in repeating the list of obscure architecture characters everywhere. Passes toolstash/buildall. Change-Id: I6a07f74188ac592ef229a7c65848a9ba93013cdb Reviewed-on: https://go-review.googlesource.com/21569 Run-TryBot: Matthew Dempsky Reviewed-by: Michael Hudson-Doyle Reviewed-by: Brad Fitzpatrick --- src/cmd/link/internal/ld/dwarf.go | 21 ++++++--------------- src/cmd/link/internal/ld/elf.go | 10 ++++------ src/cmd/link/internal/ld/symtab.go | 6 ++---- 3 files changed, 12 insertions(+), 25 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index fd177cfef0..4465a727a5 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -2169,18 +2169,10 @@ func dwarfaddshstrings(shstrtab *LSym) { elfstrdbg[ElfStrDebugStr] = Addstring(shstrtab, ".debug_str") elfstrdbg[ElfStrGDBScripts] = 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") - } + elfstrdbg[ElfStrRelDebugInfo] = Addstring(shstrtab, elfRelType+".debug_info") + elfstrdbg[ElfStrRelDebugAranges] = Addstring(shstrtab, elfRelType+".debug_aranges") + elfstrdbg[ElfStrRelDebugLine] = Addstring(shstrtab, elfRelType+".debug_line") + elfstrdbg[ElfStrRelDebugFrame] = Addstring(shstrtab, elfRelType+".debug_frame") infosym = Linklookup(Ctxt, ".debug_info", 0) infosym.Attr |= AttrHidden @@ -2222,10 +2214,9 @@ func dwarfaddelfsectionsyms() { func dwarfaddelfrelocheader(elfstr int, shdata *ElfShdr, off int64, size int64) { sh := newElfShdr(elfstrdbg[elfstr]) - switch Thearch.Thechar { - case '0', '6', '7', '9', 'z': + if elfRelType == ".rela" { sh.type_ = SHT_RELA - default: + } else { sh.type_ = SHT_REL } diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index ffb7c4bdde..3b40c66592 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -1885,10 +1885,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 } @@ -1967,10 +1966,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)) diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index 3258bc1ff9..0fe0a68c65 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -66,8 +66,7 @@ func putelfstr(s string) int { } 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 +74,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)) -- cgit v1.3-5-g9baa From a037c73ccfc7c35a389e95ffa7996c8dd38e0cde Mon Sep 17 00:00:00 2001 From: Ryan Brown Date: Mon, 14 Mar 2016 09:23:04 -0700 Subject: cmd/link: generate DWARF info using symbols This updates dwarf.go to generate debug information as symbols instead of directly writing to the output file. This should make it easier to move generation of some of the debug info into the compiler. Change-Id: Id2358988bfb689865ab4d68f82716f0676336df4 Reviewed-on: https://go-review.googlesource.com/20679 Reviewed-by: David Crawshaw Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot --- src/cmd/internal/obj/link.go | 4 + src/cmd/link/internal/amd64/asm.go | 22 +- src/cmd/link/internal/arm/asm.go | 21 +- src/cmd/link/internal/arm64/asm.go | 21 +- src/cmd/link/internal/ld/data.go | 114 +++ src/cmd/link/internal/ld/dwarf.go | 1493 +++++++++++++---------------------- src/cmd/link/internal/ld/elf.go | 23 +- src/cmd/link/internal/ld/macho.go | 29 +- src/cmd/link/internal/ld/symtab.go | 12 - src/cmd/link/internal/mips64/asm.go | 10 +- src/cmd/link/internal/ppc64/asm.go | 10 +- src/cmd/link/internal/s390x/asm.go | 6 +- src/cmd/link/internal/x86/asm.go | 24 +- 13 files changed, 727 insertions(+), 1062 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 24f028f737..9c06e8dec6 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -423,6 +423,8 @@ const ( SCONST SDYNIMPORT SHOSTOBJ + SDWARFSECT + SDWARFINFO SSUB = 1 << 8 SMASK = SSUB - 1 SHIDDEN = 1 << 9 @@ -495,6 +497,8 @@ const ( // of a JMP instruction, by encoding the address into the instruction. // The stack nosplit check ignores this since it is not a function call. R_JMPMIPS + // R_DWARFREF resolves to the offset of the symbol from its section. + R_DWARFREF // Platform dependent relocations. Architectures with fixed width instructions // have the inherent issue that a 32-bit (or 64-bit!) displacement cannot be diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index d809f6e8ed..25232e6e01 100644 --- a/src/cmd/link/internal/amd64/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -650,19 +650,11 @@ func asmb() { 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() } @@ -715,11 +707,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) } @@ -736,8 +728,6 @@ func asmb() { fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) } - ld.Dwarfemitdebugsections() - if ld.Linkmode == ld.LinkExternal { ld.Elfemitreloc() } @@ -762,8 +752,6 @@ func asmb() { fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) } - ld.Dwarfemitdebugsections() - case obj.Hdarwin: if ld.Linkmode == ld.LinkExternal { ld.Machoemitreloc() diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go index bb90cf77b6..e2718bfac8 100644 --- a/src/cmd/link/internal/arm/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -597,19 +597,11 @@ func asmb() { 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()) } @@ -627,7 +619,7 @@ func asmb() { 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))) } @@ -649,11 +641,6 @@ func asmb() { 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() } diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index 250f0afb16..8227dc0d28 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -435,19 +435,11 @@ func asmb() { 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()) } @@ -465,7 +457,7 @@ func asmb() { 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))) } @@ -487,11 +479,6 @@ func asmb() { 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() } diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index fe74cc9208..6bbd6c7d5c 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -84,6 +84,20 @@ func setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 { return off + wid } +func Addbytes(ctxt *Link, s *LSym, bytes []byte) int64 { + if s.Type == 0 { + s.Type = obj.SDATA + } + s.Attr |= AttrReachable + s.Size += int64(len(bytes)) + if int64(int(s.Size)) != s.Size { + log.Fatalf("Addbytes size %d too long", s.Size) + } + s.P = append(s.P, bytes...) + + return s.Size +} + func adduintxx(ctxt *Link, s *LSym, v uint64, wid int) int64 { off := s.Size setuintxx(ctxt, s, off, v, int64(wid)) @@ -489,6 +503,25 @@ func relocsym(s *LSym) { 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 && Thearch.Thechar == '6' { + o = 0 + } + break + } + o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr) + // 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) { @@ -614,6 +647,9 @@ func reloc() { for s := datap; s != nil; s = s.Next { relocsym(s) } + for s := dwarfp; s != nil; s = s.Next { + relocsym(s) + } } func dynrelocsym(s *LSym) { @@ -893,6 +929,14 @@ func Datblk(addr int64, size int64) { 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 // strnput writes the first n bytes of s. @@ -1691,6 +1735,40 @@ func dodata() { Diag("read-only data segment too large") } + dwarfgeneratedebugsyms() + + 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) + growdatsize(&datsize, s) + sect.Length = uint64(datsize) - sect.Vaddr + } + + 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 + growdatsize(&datsize, s) + } + sect.Length = uint64(datsize) - sect.Vaddr + } + + // The compiler uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. + if datsize != int64(uint32(datsize)) { + Diag("dwarf segment too large") + } + /* number the sections */ n := int32(1) @@ -1706,6 +1784,10 @@ func dodata() { sect.Extnum = int16(n) n++ } + for sect := Segdwarf.Sect; sect != nil; sect = sect.Next { + sect.Extnum = int16(n) + n++ + } } // Add buildid to beginning of text segment, on non-ELF systems. @@ -1857,6 +1939,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 { @@ -1884,6 +1989,15 @@ func address() { sub.Value += sym.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 { + sub.Value += sym.Value + } + } if Buildmode == BuildmodeShared { s := Linklookup(Ctxt, "go.link.abihashbytes", 0) diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 4465a727a5..eaa0bdbb41 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) { +func addrput(s *LSym, addr int64) { switch Thearch.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,16 @@ 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) + for _, x := range b { + Adduint8(Ctxt, s, x) + } } /* @@ -462,24 +401,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 +448,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 +497,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 +506,16 @@ 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.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 +529,150 @@ 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) +func find(name string) *LSym { + return Linkrlookup(Ctxt, infoprefix+name, 0) +} + +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 Thearch.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+Thearch.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, uint8(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, uint8(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, uint8(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, uint8(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), @@ -753,21 +683,13 @@ func putattr(abbrev int, form int, cls int, value int64, data interface{}) { if data == nil { Diag("dwarf: null reference in %d", abbrev) if Thearch.Ptrsize == 8 { - Thearch.Vput(0) // invalid dwarf, gdb will complain. + 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, Thearch.Ptrsize) } case DW_FORM_ref1, // reference within the compilation unit @@ -786,34 +708,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 +813,49 @@ 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.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, "") + return mustFind("") } if !strings.HasPrefix(gotype.Name, "type.") { Diag("dwarf: type name doesn't start with \"type.\": %s", gotype.Name) - return mustFind(&dwtypes, "") + return mustFind("") } 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 +864,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 +874,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 +949,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 +990,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, "")) + die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name, 0) + newrefattr(die, DW_AT_type, mustFind("")) } 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 +1038,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 +1054,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 +1070,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 +1094,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 +1104,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 +1128,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 +1152,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(Thearch.Ptrsize) indirect_key = true } if valsize > MaxValSize { - valsize = Thearch.Ptrsize + valsize = int64(Thearch.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*int64(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*int64(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 - 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")) - - 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)) - } + 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", 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 Thearch.Regsize > Thearch.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(Thearch.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*int64(keysize)+BucketSize*int64(valsize)+int64(Thearch.Regsize), 0) + }) // Construct hash - 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 - 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 +1248,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 - 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)+int64(elemsize), nil) + }) // waitq - 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 - 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 +1302,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) @@ -1386,23 +1357,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 +1399,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 +1406,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 - 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,26 +1437,30 @@ 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) + 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) files := make([]*LSym, Ctxt.Nhistfile) @@ -1512,25 +1469,28 @@ func writelines() { } for i := 0; int32(i) < Ctxt.Nhistfile; i++ { - strnput(files[i].Name, len(files[i].Name)+4) + Addstring(ls, files[i].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(Thearch.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 @@ -1538,7 +1498,7 @@ func writelines() { for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next { 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 @@ -1568,12 +1528,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) @@ -1610,7 +1570,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 +1581,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,8 +1602,16 @@ 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 } /* @@ -1675,47 +1643,49 @@ 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 + Adduint32(Ctxt, fs, CIERESERVE) // initial length, must be multiple of thearch.ptrsize + 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) // guess + uleb128put(fs, int64(Thearch.Dwarfreglr)) // return_address_register - Cput(DW_CFA_def_cfa) + Adduint8(Ctxt, fs, DW_CFA_def_cfa) - uleb128put(int64(Thearch.Dwarfregsp)) // register SP (**ABI-dependent, defined in l.h) + uleb128put(fs, int64(Thearch.Dwarfregsp)) // register SP (**ABI-dependent, defined in l.h) if haslinkregister() { - uleb128put(int64(0)) // offset + uleb128put(fs, int64(0)) // offset } else { - uleb128put(int64(Thearch.Ptrsize)) // offset + uleb128put(fs, int64(Thearch.Ptrsize)) // offset } - Cput(DW_CFA_offset_extended) - uleb128put(int64(Thearch.Dwarfreglr)) // return address + Adduint8(Ctxt, fs, DW_CFA_offset_extended) + uleb128put(fs, int64(Thearch.Dwarfreglr)) // return address if haslinkregister() { - uleb128put(int64(0) / DATAALIGNMENTFACTOR) // at cfa - 0 + uleb128put(fs, int64(0)/DATAALIGNMENTFACTOR) // at cfa - 0 } else { - uleb128put(int64(-Thearch.Ptrsize) / DATAALIGNMENTFACTOR) // at cfa - x*4 + uleb128put(fs, int64(-Thearch.Ptrsize)/DATAALIGNMENTFACTOR) // at cfa - x*4 } // 4 is to exclude the length field. - pad := CIERESERVE + frameo + 4 - Cpos() + pad := CIERESERVE + 4 - fs.Size if pad < 0 { Exitf("dwarf: CIERESERVE too small by %d bytes.", -pad) } - strnput("", int(pad)) + Addbytes(Ctxt, fs, zeros[:pad]) var deltaBuf []byte var pcsp Pciter @@ -1754,21 +1724,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*Thearch.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 +1744,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 +1759,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(Thearch.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, int64(cusize), 0) } - - Cflush() + return prev } /* @@ -1837,48 +1803,49 @@ 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 @@ -1894,78 +1861,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) - - value := compunit.offs - COMPUNITHEADERSIZE // debug_info_offset - if Linkmode == LinkExternal { - adddwarfrel(arangessec, infosym, sectionstart, 4, value) - } else { - Thearch.Lput(uint32(value)) - } + unitlength := uint32(headersize) + 4*uint32(Thearch.Ptrsize) - 4 + Adduint32(Ctxt, s, unitlength) // unit_length (*) + Adduint16(Ctxt, s, 2) // dwarf version (appendix F) - Cput(uint8(Thearch.Ptrsize)) // address_size - Cput(0) // segment_size - strnput("", headersize-(4+2+4+1+1)) // align to thearch.ptrsize + adddwarfref(Ctxt, s, compunit.sym, 4) - 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(Thearch.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 +1911,49 @@ func addmachodwarfsect(prev *Section, name string) *Section { * passes. * */ -func Dwarfemitdebugsections() { +func dwarfgeneratedebugsyms() { if Debug['w'] != 0 { // disable dwarf 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, "") + newdie(&dwtypes, DW_ABRV_NULLTYPE, "", 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_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 +1962,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,403 +1979,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) + // Need to reorder symbols so SDWARFINFO is after all SDWARFSECT + // (but we need to generate dies before writepub) + writeinfo(last) + infosyms := last.Next - arangeso = writearanges() - arangessize = Cpos() - arangeso - align(arangessize) - - gdbscripto = writegdbscript() - gdbscriptsize = Cpos() - gdbscripto - align(gdbscriptsize) - - 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 { - elfstrdbg[ElfStrRelDebugInfo] = Addstring(shstrtab, elfRelType+".debug_info") - elfstrdbg[ElfStrRelDebugAranges] = Addstring(shstrtab, elfRelType+".debug_aranges") - elfstrdbg[ElfStrRelDebugLine] = Addstring(shstrtab, elfRelType+".debug_line") - elfstrdbg[ElfStrRelDebugFrame] = Addstring(shstrtab, elfRelType+".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]) - if elfRelType == ".rela" { - sh.type_ = SHT_RELA - } else { - 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) } /* @@ -2461,13 +2043,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 3b40c66592..035826df7c 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -1622,6 +1622,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 @@ -1739,6 +1742,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, dwarfp) + } } func addgonote(sectionName string, tag uint32, desc []byte) { @@ -2067,6 +2073,9 @@ 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) { @@ -2432,6 +2441,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 { @@ -2443,7 +2455,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") @@ -2467,8 +2486,6 @@ elfobj: sh.off = uint64(symo) + uint64(Symsize) sh.size = uint64(len(Elfstrdat)) sh.addralign = 1 - - dwarfaddelfheaders() } /* Main header */ diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index d60203fb91..cafc6b0382 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -356,7 +356,7 @@ 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 + if sect.Rwx&1 == 0 && segname != "__DWARF" && (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 // complains about absolute relocs in __TEXT, so if the section is not @@ -411,6 +411,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() { @@ -492,6 +496,20 @@ 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 { default: @@ -586,11 +604,6 @@ func Asmbmacho() { 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) @@ -876,5 +889,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, dwarfp) + } } diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index 0fe0a68c65..167176cc2d 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -195,18 +195,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) diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go index 8249c54e45..d0977e9b00 100644 --- a/src/cmd/link/internal/mips64/asm.go +++ b/src/cmd/link/internal/mips64/asm.go @@ -147,6 +147,9 @@ func asmb() { 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 @@ -161,7 +164,7 @@ func asmb() { 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))) } @@ -180,11 +183,6 @@ func asmb() { 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() } diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go index ae69799abf..4c2131dfc6 100644 --- a/src/cmd/link/internal/ppc64/asm.go +++ b/src/cmd/link/internal/ppc64/asm.go @@ -868,6 +868,9 @@ func asmb() { 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 @@ -882,7 +885,7 @@ func asmb() { 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))) } @@ -901,11 +904,6 @@ func asmb() { 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() } diff --git a/src/cmd/link/internal/s390x/asm.go b/src/cmd/link/internal/s390x/asm.go index 75a8206174..c5e2d187b8 100644 --- a/src/cmd/link/internal/s390x/asm.go +++ b/src/cmd/link/internal/s390x/asm.go @@ -539,6 +539,9 @@ func asmb() { 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 @@ -552,7 +555,7 @@ func asmb() { 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)) @@ -566,7 +569,6 @@ func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) } - ld.Dwarfemitdebugsections() if ld.Linkmode == ld.LinkExternal { ld.Elfemitreloc() diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go index 97fccf3ee6..7da5dd02be 100644 --- a/src/cmd/link/internal/x86/asm.go +++ b/src/cmd/link/internal/x86/asm.go @@ -643,19 +643,11 @@ func asmb() { 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()) } @@ -672,7 +664,7 @@ func asmb() { 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 +675,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)) } @@ -698,11 +690,6 @@ func asmb() { 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() } @@ -726,7 +713,6 @@ func asmb() { if ld.Debug['v'] != 0 { fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime()) } - ld.Dwarfemitdebugsections() case obj.Hdarwin: if ld.Linkmode == ld.LinkExternal { -- cgit v1.3-5-g9baa From c6e11fe03765e3fe1fc68bd794625ca0ecd833be Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 6 Apr 2016 12:01:40 -0700 Subject: cmd: add new common architecture representation Information about CPU architectures (e.g., name, family, byte ordering, pointer and register size) is currently redundantly scattered around the source tree. Instead consolidate the basic information into a single new package cmd/internal/sys. Also, introduce new sys.I386, sys.AMD64, etc. names for the constants '8', '6', etc. and replace most uses of the latter. The notable exceptions are a couple of error messages that still refer to the old char-based toolchain names and function reltype in cmd/link. Passes toolstash/buildall. Change-Id: I8a6f0cbd49577ec1672a98addebc45f767e36461 Reviewed-on: https://go-review.googlesource.com/21623 Reviewed-by: Michael Hudson-Doyle Reviewed-by: Brad Fitzpatrick Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot --- src/cmd/asm/internal/asm/asm.go | 49 +++++----- src/cmd/asm/internal/asm/parse.go | 16 ++-- src/cmd/compile/internal/amd64/galign.go | 12 +-- src/cmd/compile/internal/arm/galign.go | 7 +- src/cmd/compile/internal/arm64/galign.go | 7 +- src/cmd/compile/internal/gc/cgen.go | 88 +++++++++--------- src/cmd/compile/internal/gc/gen.go | 3 +- src/cmd/compile/internal/gc/go.go | 5 +- src/cmd/compile/internal/gc/gsubr.go | 19 ++-- src/cmd/compile/internal/gc/main.go | 21 +++-- src/cmd/compile/internal/gc/pgen.go | 5 +- src/cmd/compile/internal/gc/plive.go | 3 +- src/cmd/compile/internal/gc/reg.go | 7 +- src/cmd/compile/internal/gc/ssa.go | 7 +- src/cmd/compile/internal/gc/walk.go | 10 +-- src/cmd/compile/internal/mips64/galign.go | 10 +-- src/cmd/compile/internal/ppc64/galign.go | 11 +-- src/cmd/compile/internal/x86/galign.go | 7 +- src/cmd/dist/buildtool.go | 1 + src/cmd/internal/obj/arm/obj5.go | 15 ++-- src/cmd/internal/obj/arm64/obj7.go | 15 ++-- src/cmd/internal/obj/data.go | 2 +- src/cmd/internal/obj/link.go | 19 ++-- src/cmd/internal/obj/mips/obj0.go | 22 ++--- src/cmd/internal/obj/objfile.go | 3 +- src/cmd/internal/obj/pcln.go | 4 +- src/cmd/internal/obj/ppc64/obj9.go | 22 ++--- src/cmd/internal/obj/s390x/objz.go | 15 ++-- src/cmd/internal/obj/sym.go | 3 +- src/cmd/internal/obj/x86/asm6.go | 2 +- src/cmd/internal/obj/x86/obj6.go | 55 +++++------- src/cmd/internal/sys/arch.go | 145 ++++++++++++++++++++++++++++++ src/cmd/link/internal/amd64/asm.go | 2 +- src/cmd/link/internal/amd64/l.go | 5 -- src/cmd/link/internal/amd64/obj.go | 11 +-- src/cmd/link/internal/arm/l.go | 2 - src/cmd/link/internal/arm/obj.go | 9 +- src/cmd/link/internal/arm64/asm.go | 2 +- src/cmd/link/internal/arm64/l.go | 2 - src/cmd/link/internal/arm64/obj.go | 9 +- src/cmd/link/internal/ld/arch.go | 97 -------------------- src/cmd/link/internal/ld/data.go | 57 ++++++------ src/cmd/link/internal/ld/deadcode.go | 3 +- src/cmd/link/internal/ld/decodesym.go | 77 ++++++++-------- src/cmd/link/internal/ld/dwarf.go | 44 ++++----- src/cmd/link/internal/ld/elf.go | 92 ++++++++++--------- src/cmd/link/internal/ld/ldelf.go | 26 +++--- src/cmd/link/internal/ld/ldmacho.go | 18 ++-- src/cmd/link/internal/ld/ldpe.go | 3 +- src/cmd/link/internal/ld/lib.go | 53 +++++------ src/cmd/link/internal/ld/link.go | 25 ++---- src/cmd/link/internal/ld/macho.go | 46 ++++------ src/cmd/link/internal/ld/pcln.go | 38 ++++---- src/cmd/link/internal/ld/pe.go | 29 +++--- src/cmd/link/internal/ld/pobj.go | 9 +- src/cmd/link/internal/ld/sym.go | 33 +++---- src/cmd/link/internal/ld/symtab.go | 5 +- src/cmd/link/internal/mips64/asm.go | 9 +- src/cmd/link/internal/mips64/l.go | 2 - src/cmd/link/internal/mips64/obj.go | 15 ++-- src/cmd/link/internal/ppc64/l.go | 2 - src/cmd/link/internal/ppc64/obj.go | 17 ++-- src/cmd/link/internal/s390x/l.go | 5 -- src/cmd/link/internal/s390x/obj.go | 9 +- src/cmd/link/internal/x86/asm.go | 4 +- src/cmd/link/internal/x86/l.go | 3 - src/cmd/link/internal/x86/obj.go | 9 +- 67 files changed, 639 insertions(+), 743 deletions(-) create mode 100644 src/cmd/internal/sys/arch.go delete mode 100644 src/cmd/link/internal/ld/arch.go (limited to 'src/cmd/link') diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go index 950fd735c9..d674914c67 100644 --- a/src/cmd/asm/internal/asm/asm.go +++ b/src/cmd/asm/internal/asm/asm.go @@ -13,6 +13,7 @@ import ( "cmd/asm/internal/flags" "cmd/asm/internal/lex" "cmd/internal/obj" + "cmd/internal/sys" ) // TODO: configure the architecture @@ -23,14 +24,14 @@ var testOut *bytes.Buffer // Gathers output when testing. // If doLabel is set, it also defines the labels collect for this Prog. func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) { if cond != "" { - switch p.arch.Thechar { - case '5': + switch p.arch.Family { + case sys.ARM: if !arch.ARMConditionCodes(prog, cond) { p.errorf("unrecognized condition code .%q", cond) return } - case '7': + case sys.ARM64: if !arch.ARM64Suffix(prog, cond) { p.errorf("unrecognized suffix .%q", cond) return @@ -361,7 +362,7 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) { target = &a[1] prog.From = a[0] case 3: - if p.arch.Thechar == '9' { + if p.arch.Family == sys.PPC64 { // Special 3-operand jumps. // First two must be constants; a[1] is a register number. target = &a[2] @@ -378,7 +379,7 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) { prog.Reg = reg break } - if p.arch.Thechar == '0' { + if p.arch.Family == sys.MIPS64 { // 3-operand jumps. // First two must be registers target = &a[2] @@ -386,7 +387,7 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) { prog.Reg = p.getRegister(prog, op, &a[1]) break } - if p.arch.Thechar == 'z' { + if p.arch.Family == sys.S390X { // 3-operand jumps. target = &a[2] prog.From = a[0] @@ -438,7 +439,7 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) { // JMP 4(R0) prog.To = *target // On the ppc64, 9a encodes BR (CTR) as BR CTR. We do the same. - if p.arch.Thechar == '9' && target.Offset == 0 { + if p.arch.Family == sys.PPC64 && target.Offset == 0 { prog.To.Type = obj.TYPE_REG } case target.Type == obj.TYPE_CONST: @@ -492,14 +493,14 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { prog.From = a[0] // prog.To is no address. } - if p.arch.Thechar == '9' && arch.IsPPC64NEG(op) { + if p.arch.Family == sys.PPC64 && arch.IsPPC64NEG(op) { // NEG: From and To are both a[0]. prog.To = a[0] prog.From = a[0] break } case 2: - if p.arch.Thechar == '5' { + if p.arch.Family == sys.ARM { if arch.IsARMCMP(op) { prog.From = a[0] prog.Reg = p.getRegister(prog, op, &a[1]) @@ -532,11 +533,11 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { prog.Reg = p.getRegister(prog, op, &a[1]) break } - } else if p.arch.Thechar == '7' && arch.IsARM64CMP(op) { + } else if p.arch.Family == sys.ARM64 && arch.IsARM64CMP(op) { prog.From = a[0] prog.Reg = p.getRegister(prog, op, &a[1]) break - } else if p.arch.Thechar == '0' { + } else if p.arch.Family == sys.MIPS64 { if arch.IsMIPS64CMP(op) || arch.IsMIPS64MUL(op) { prog.From = a[0] prog.Reg = p.getRegister(prog, op, &a[1]) @@ -546,12 +547,12 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { prog.From = a[0] prog.To = a[1] case 3: - switch p.arch.Thechar { - case '0': + switch p.arch.Family { + case sys.MIPS64: prog.From = a[0] prog.Reg = p.getRegister(prog, op, &a[1]) prog.To = a[2] - case '5': + case sys.ARM: // Special cases. if arch.IsARMSTREX(op) { /* @@ -567,7 +568,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { prog.From = a[0] prog.Reg = p.getRegister(prog, op, &a[1]) prog.To = a[2] - case '7': + case sys.ARM64: // ARM64 instructions with one input and two outputs. if arch.IsARM64STLXR(op) { prog.From = a[0] @@ -582,11 +583,11 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { prog.From = a[0] prog.Reg = p.getRegister(prog, op, &a[1]) prog.To = a[2] - case '6', '8': + case sys.AMD64, sys.I386: prog.From = a[0] prog.From3 = newAddr(a[1]) prog.To = a[2] - case '9': + case sys.PPC64: if arch.IsPPC64CMP(op) { // CMPW etc.; third argument is a CR register that goes into prog.Reg. prog.From = a[0] @@ -612,7 +613,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { p.errorf("invalid addressing modes for %s instruction", obj.Aconv(op)) return } - case 'z': + case sys.S390X: if arch.IsS390xWithLength(op) || arch.IsS390xWithIndex(op) { prog.From = a[1] prog.From3 = newAddr(a[0]) @@ -626,7 +627,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { return } case 4: - if p.arch.Thechar == '5' && arch.IsARMMULA(op) { + if p.arch.Family == sys.ARM && arch.IsARMMULA(op) { // All must be registers. p.getRegister(prog, op, &a[0]) r1 := p.getRegister(prog, op, &a[1]) @@ -639,14 +640,14 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { prog.Reg = r1 break } - if p.arch.Thechar == '7' { + if p.arch.Family == sys.ARM64 { prog.From = a[0] prog.Reg = p.getRegister(prog, op, &a[1]) prog.From3 = newAddr(a[2]) prog.To = a[3] break } - if p.arch.Thechar == '9' && arch.IsPPC64RLD(op) { + if p.arch.Family == sys.PPC64 && arch.IsPPC64RLD(op) { // 2nd operand must always be a register. // TODO: Do we need to guard this with the instruction type? // That is, are there 4-operand instructions without this property? @@ -656,7 +657,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { prog.To = a[3] break } - if p.arch.Thechar == 'z' { + if p.arch.Family == sys.S390X { prog.From = a[1] prog.Reg = p.getRegister(prog, op, &a[2]) prog.From3 = newAddr(a[0]) @@ -666,7 +667,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { p.errorf("can't handle %s instruction with 4 operands", obj.Aconv(op)) return case 5: - if p.arch.Thechar == '9' && arch.IsPPC64RLD(op) { + if p.arch.Family == sys.PPC64 && arch.IsPPC64RLD(op) { // Always reg, reg, con, con, reg. (con, con is a 'mask'). prog.From = a[0] prog.Reg = p.getRegister(prog, op, &a[1]) @@ -688,7 +689,7 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) { p.errorf("can't handle %s instruction with 5 operands", obj.Aconv(op)) return case 6: - if p.arch.Thechar == '5' && arch.IsARMMRC(op) { + if p.arch.Family == sys.ARM && arch.IsARMMRC(op) { // Strange special case: MCR, MRC. prog.To.Type = obj.TYPE_CONST x0 := p.getConstant(prog, op, &a[0]) diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go index ee37439962..40206e6dc1 100644 --- a/src/cmd/asm/internal/asm/parse.go +++ b/src/cmd/asm/internal/asm/parse.go @@ -19,6 +19,7 @@ import ( "cmd/asm/internal/flags" "cmd/asm/internal/lex" "cmd/internal/obj" + "cmd/internal/sys" ) type Parser struct { @@ -130,7 +131,7 @@ func (p *Parser) line() bool { for { tok = p.lex.Next() if len(operands) == 0 && len(items) == 0 { - if (p.arch.Thechar == '5' || p.arch.Thechar == '7') && tok == '.' { + if p.arch.InFamily(sys.ARM, sys.ARM64) && tok == '.' { // ARM conditionals. tok = p.lex.Next() str := p.lex.Text() @@ -420,7 +421,7 @@ func (p *Parser) atStartOfRegister(name string) bool { // We have consumed the register or R prefix. func (p *Parser) atRegisterShift() bool { // ARM only. - if p.arch.Thechar != '5' { + if p.arch.Family != sys.ARM { return false } // R1<<... @@ -476,15 +477,14 @@ func (p *Parser) register(name string, prefix rune) (r1, r2 int16, scale int8, o if c == ':' || c == ',' || c == '+' { // 2nd register; syntax (R1+R2) etc. No two architectures agree. // Check the architectures match the syntax. - char := p.arch.Thechar switch p.next().ScanToken { case ',': - if char != '5' && char != '7' { + if !p.arch.InFamily(sys.ARM, sys.ARM64) { p.errorf("(register,register) not supported on this architecture") return } case '+': - if char != '9' { + if p.arch.Family != sys.PPC64 { p.errorf("(register+register) not supported on this architecture") return } @@ -649,7 +649,7 @@ func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) { a.Reg = r1 if r2 != 0 { // TODO: Consistency in the encoding would be nice here. - if p.arch.Thechar == '5' || p.arch.Thechar == '7' { + if p.arch.InFamily(sys.ARM, sys.ARM64) { // Special form // ARM: destination register pair (R1, R2). // ARM64: register pair (R1, R2) for LDP/STP. @@ -662,7 +662,7 @@ func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) { // Nothing may follow return } - if p.arch.Thechar == '9' { + if p.arch.Family == sys.PPC64 { // Special form for PPC64: (R1+R2); alias for (R1)(R2*1). if prefix != 0 || scale != 0 { p.errorf("illegal address mode for register+register") @@ -752,7 +752,7 @@ ListLoop: // register number is ARM-specific. It returns the number of the specified register. func (p *Parser) registerNumber(name string) uint16 { - if p.arch.Thechar == '5' && name == "g" { + if p.arch.Family == sys.ARM && name == "g" { return 10 } if name[0] != 'R' { diff --git a/src/cmd/compile/internal/amd64/galign.go b/src/cmd/compile/internal/amd64/galign.go index 14721ea35b..461ef2ada1 100644 --- a/src/cmd/compile/internal/amd64/galign.go +++ b/src/cmd/compile/internal/amd64/galign.go @@ -18,12 +18,7 @@ var ( ) func betypeinit() { - gc.Widthptr = 8 - gc.Widthint = 8 - gc.Widthreg = 8 if obj.Getgoarch() == "amd64p32" { - gc.Widthptr = 4 - gc.Widthint = 4 addptr = x86.AADDL movptr = x86.AMOVL leaptr = x86.ALEAL @@ -42,12 +37,9 @@ func Main() { resvd = append(resvd, x86.REG_BP) } - gc.Thearch.Thechar = '6' - gc.Thearch.Thestring = "amd64" - gc.Thearch.Thelinkarch = &x86.Linkamd64 + gc.Thearch.LinkArch = &x86.Linkamd64 if obj.Getgoarch() == "amd64p32" { - gc.Thearch.Thestring = "amd64p32" - gc.Thearch.Thelinkarch = &x86.Linkamd64p32 + gc.Thearch.LinkArch = &x86.Linkamd64p32 } gc.Thearch.REGSP = x86.REGSP gc.Thearch.REGCTXT = x86.REGCTXT diff --git a/src/cmd/compile/internal/arm/galign.go b/src/cmd/compile/internal/arm/galign.go index e05f4d06bb..afd86e44c8 100644 --- a/src/cmd/compile/internal/arm/galign.go +++ b/src/cmd/compile/internal/arm/galign.go @@ -11,15 +11,10 @@ import ( ) func betypeinit() { - gc.Widthptr = 4 - gc.Widthint = 4 - gc.Widthreg = 4 } func Main() { - gc.Thearch.Thechar = '5' - gc.Thearch.Thestring = "arm" - gc.Thearch.Thelinkarch = &arm.Linkarm + gc.Thearch.LinkArch = &arm.Linkarm gc.Thearch.REGSP = arm.REGSP gc.Thearch.REGCTXT = arm.REGCTXT gc.Thearch.REGCALLX = arm.REG_R1 diff --git a/src/cmd/compile/internal/arm64/galign.go b/src/cmd/compile/internal/arm64/galign.go index 7e1226fee1..17c851cb14 100644 --- a/src/cmd/compile/internal/arm64/galign.go +++ b/src/cmd/compile/internal/arm64/galign.go @@ -10,15 +10,10 @@ import ( ) func betypeinit() { - gc.Widthptr = 8 - gc.Widthint = 8 - gc.Widthreg = 8 } func Main() { - gc.Thearch.Thechar = '7' - gc.Thearch.Thestring = "arm64" - gc.Thearch.Thelinkarch = &arm64.Linkarm64 + gc.Thearch.LinkArch = &arm64.Linkarm64 gc.Thearch.REGSP = arm64.REGSP gc.Thearch.REGCTXT = arm64.REGCTXT gc.Thearch.REGCALLX = arm64.REGRT1 diff --git a/src/cmd/compile/internal/gc/cgen.go b/src/cmd/compile/internal/gc/cgen.go index c594ad4c11..a9cedf7cfc 100644 --- a/src/cmd/compile/internal/gc/cgen.go +++ b/src/cmd/compile/internal/gc/cgen.go @@ -7,6 +7,7 @@ package gc import ( "cmd/internal/obj" "cmd/internal/obj/ppc64" + "cmd/internal/sys" "fmt" ) @@ -88,7 +89,7 @@ func cgen_wb(n, res *Node, wb bool) { if !res.Addable { if n.Ullman > res.Ullman { - if Ctxt.Arch.Regsize == 4 && Is64(n.Type) { + if Ctxt.Arch.RegSize == 4 && Is64(n.Type) { var n1 Node Tempname(&n1, n.Type) Cgen(n, &n1) @@ -127,7 +128,7 @@ func cgen_wb(n, res *Node, wb bool) { f = false } - if !n.Type.IsComplex() && Ctxt.Arch.Regsize == 8 && !wb { + if !n.Type.IsComplex() && Ctxt.Arch.RegSize == 8 && !wb { a := Thearch.Optoas(OAS, res.Type) var addr obj.Addr if Thearch.Sudoaddable(a, res, &addr) { @@ -151,7 +152,7 @@ func cgen_wb(n, res *Node, wb bool) { } } - if Ctxt.Arch.Thechar == '8' { + if Ctxt.Arch.Family == sys.I386 { // no registers to speak of var n1, n2 Node Tempname(&n1, n.Type) @@ -203,7 +204,7 @@ func cgen_wb(n, res *Node, wb bool) { // Write barrier now handled. Code below this line can ignore wb. - if Ctxt.Arch.Thechar == '5' { // TODO(rsc): Maybe more often? + if Ctxt.Arch.Family == sys.ARM { // TODO(rsc): Maybe more often? // if both are addressable, move if n.Addable && res.Addable { if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || n.Type.IsComplex() || res.Type.IsComplex() { @@ -246,12 +247,12 @@ func cgen_wb(n, res *Node, wb bool) { return } - if (Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8') && n.Addable { + if Ctxt.Arch.InFamily(sys.AMD64, sys.I386) && n.Addable { Thearch.Gmove(n, res) return } - if Ctxt.Arch.Thechar == '0' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' { + if Ctxt.Arch.InFamily(sys.ARM64, sys.MIPS64, sys.PPC64) { // if both are addressable, move if n.Addable { if n.Op == OREGISTER || res.Op == OREGISTER { @@ -268,7 +269,7 @@ func cgen_wb(n, res *Node, wb bool) { } // if n is sudoaddable generate addr and move - if Ctxt.Arch.Thechar == '5' && !Is64(n.Type) && !Is64(res.Type) && !n.Type.IsComplex() && !res.Type.IsComplex() { + if Ctxt.Arch.Family == sys.ARM && !Is64(n.Type) && !Is64(res.Type) && !n.Type.IsComplex() && !res.Type.IsComplex() { a := Thearch.Optoas(OAS, n.Type) var addr obj.Addr if Thearch.Sudoaddable(a, n, &addr) { @@ -310,7 +311,7 @@ func cgen_wb(n, res *Node, wb bool) { } // 64-bit ops are hard on 32-bit machine. - if Ctxt.Arch.Regsize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) { + if Ctxt.Arch.RegSize == 4 && (Is64(n.Type) || Is64(res.Type) || n.Left != nil && Is64(n.Left.Type)) { switch n.Op { // math goes to cgen64. case OMINUS, @@ -334,7 +335,7 @@ func cgen_wb(n, res *Node, wb bool) { return } - if !n.Type.IsComplex() && Ctxt.Arch.Regsize == 8 { + if !n.Type.IsComplex() && Ctxt.Arch.RegSize == 8 { a := Thearch.Optoas(OAS, n.Type) var addr obj.Addr if Thearch.Sudoaddable(a, n, &addr) { @@ -401,11 +402,11 @@ func cgen_wb(n, res *Node, wb bool) { Regalloc(&n1, nl.Type, res) Cgen(nl, &n1) - if Ctxt.Arch.Thechar == '5' { + if Ctxt.Arch.Family == sys.ARM { var n2 Node Nodconst(&n2, nl.Type, 0) Thearch.Gins(a, &n2, &n1) - } else if Ctxt.Arch.Thechar == '7' { + } else if Ctxt.Arch.Family == sys.ARM64 { Thearch.Gins(a, &n1, &n1) } else { Thearch.Gins(a, nil, &n1) @@ -452,7 +453,7 @@ func cgen_wb(n, res *Node, wb bool) { return } - if Ctxt.Arch.Thechar == '8' { + if Ctxt.Arch.Family == sys.I386 { var n1 Node var n2 Node Tempname(&n2, n.Type) @@ -465,7 +466,7 @@ func cgen_wb(n, res *Node, wb bool) { var n1 Node var n2 Node - if Ctxt.Arch.Thechar == '5' { + if Ctxt.Arch.Family == sys.ARM { if nl.Addable && !Is64(nl.Type) { Regalloc(&n1, nl.Type, res) Thearch.Gmove(nl, &n1) @@ -707,7 +708,7 @@ sbop: // symmetric binary abop: // asymmetric binary var n1 Node var n2 Node - if Ctxt.Arch.Thechar == '8' { + if Ctxt.Arch.Family == sys.I386 { // no registers, sigh if Smallintconst(nr) { var n1 Node @@ -751,14 +752,14 @@ abop: // asymmetric binary Regalloc(&n1, nl.Type, res) Cgen(nl, &n1) - if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm + if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.ARM && Ctxt.Arch.Family != sys.ARM64 && Ctxt.Arch.Family != sys.PPC64 { // TODO(rsc): Check opcode for arm n2 = *nr } else { Regalloc(&n2, nr.Type, nil) Cgen(nr, &n2) } } else { - if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { // TODO(rsc): Check opcode for arm + if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.ARM && Ctxt.Arch.Family != sys.ARM64 && Ctxt.Arch.Family != sys.PPC64 { // TODO(rsc): Check opcode for arm n2 = *nr } else { Regalloc(&n2, nr.Type, res) @@ -876,8 +877,8 @@ func cgen_wbfat(n, res *Node) { // cgen_norm moves n1 to res, truncating to expected type if necessary. // n1 is a register, and cgen_norm frees it. func cgen_norm(n, n1, res *Node) { - switch Ctxt.Arch.Thechar { - case '6', '8': + switch Ctxt.Arch.Family { + case sys.AMD64, sys.I386: // We use sized math, so the result is already truncated. default: switch n.Op { @@ -980,7 +981,7 @@ func Agenr(n *Node, a *Node, res *Node) { Cgen_checknil(a) case OINDEX: - if Ctxt.Arch.Thechar == '5' { + if Ctxt.Arch.Family == sys.ARM { var p2 *obj.Prog // to be patched to panicindex. w := uint32(n.Type.Width) bounded := Debug['B'] != 0 || n.Bounded @@ -1127,7 +1128,7 @@ func Agenr(n *Node, a *Node, res *Node) { Regfree(&n2) break } - if Ctxt.Arch.Thechar == '8' { + if Ctxt.Arch.Family == sys.I386 { var p2 *obj.Prog // to be patched to panicindex. w := uint32(n.Type.Width) bounded := Debug['B'] != 0 || n.Bounded @@ -1604,7 +1605,7 @@ func Agen(n *Node, res *Node) { } func addOffset(res *Node, offset int64) { - if Ctxt.Arch.Thechar == '6' || Ctxt.Arch.Thechar == '8' { + if Ctxt.Arch.InFamily(sys.AMD64, sys.I386) { Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), Nodintconst(offset), res) return } @@ -1825,13 +1826,14 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { return case ONAME: + // Some architectures might need a temporary or other help here, + // but they don't support direct generation of a bool value yet. + // We can fix that as we go. + mayNeedTemp := Ctxt.Arch.InFamily(sys.ARM, sys.ARM64, sys.MIPS64, sys.PPC64) + if genval { - // 5g, 7g, and 9g might need a temporary or other help here, - // but they don't support direct generation of a bool value yet. - // We can fix that as we go. - switch Ctxt.Arch.Thechar { - case '0', '5', '7', '9': - Fatalf("genval 0g, 5g, 7g, 9g ONAMES not fully implemented") + if mayNeedTemp { + Fatalf("genval ONAMES not fully implemented") } Cgen(n, res) if !wantTrue { @@ -1840,7 +1842,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { return } - if n.Addable && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' { + if n.Addable && !mayNeedTemp { // no need for a temporary bgenNonZero(n, nil, wantTrue, likely, to) return @@ -1977,7 +1979,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { return } - if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) { + if Ctxt.Arch.RegSize == 4 && Is64(nr.Type) { if genval { // TODO: Teach Cmp64 to generate boolean values and remove this. bvgenjump(n, res, wantTrue, false) @@ -2015,7 +2017,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { Regfree(&n2) } else { var n1 Node - if !nl.Addable && Ctxt.Arch.Thechar == '8' { + if !nl.Addable && Ctxt.Arch.Family == sys.I386 { Tempname(&n1, nl.Type) } else { Regalloc(&n1, nl.Type, nil) @@ -2024,13 +2026,13 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { Cgen(nl, &n1) nl = &n1 - if Smallintconst(nr) && Ctxt.Arch.Thechar != '0' && Ctxt.Arch.Thechar != '9' { + if Smallintconst(nr) && Ctxt.Arch.Family != sys.MIPS64 && Ctxt.Arch.Family != sys.PPC64 { Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr) bins(nr.Type, res, op, likely, to) return } - if !nr.Addable && Ctxt.Arch.Thechar == '8' { + if !nr.Addable && Ctxt.Arch.Family == sys.I386 { nr = CgenTemp(nr) } @@ -2044,13 +2046,13 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { l, r := nl, nr // On x86, only < and <= work right with NaN; reverse if needed - if Ctxt.Arch.Thechar == '6' && nl.Type.IsFloat() && (op == OGT || op == OGE) { + if Ctxt.Arch.Family == sys.AMD64 && nl.Type.IsFloat() && (op == OGT || op == OGE) { l, r = r, l op = Brrev(op) } // MIPS does not have CMP instruction - if Ctxt.Arch.Thechar == '0' { + if Ctxt.Arch.Family == sys.MIPS64 { p := Thearch.Ginscmp(op, nr.Type, l, r, likely) Patch(p, to) return @@ -2062,8 +2064,8 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { // Handle floating point special cases. // Note that 8g has Bgen_float and is handled above. if nl.Type.IsFloat() { - switch Ctxt.Arch.Thechar { - case '5': + switch Ctxt.Arch.Family { + case sys.ARM: if genval { Fatalf("genval 5g Isfloat special cases not implemented") } @@ -2077,7 +2079,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { Patch(p, Pc) } return - case '6': + case sys.AMD64: switch n.Op { case OEQ: // neither NE nor P @@ -2111,7 +2113,7 @@ func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { } return } - case '7', '9': + case sys.ARM64, sys.PPC64: if genval { Fatalf("genval 7g, 9g Isfloat special cases not implemented") } @@ -2143,7 +2145,7 @@ func bgenNonZero(n, res *Node, wantTrue bool, likely int, to *obj.Prog) { } // MIPS does not have CMP instruction - if Thearch.Thechar == '0' { + if Thearch.LinkArch.Family == sys.MIPS64 { p := Gbranch(Thearch.Optoas(op, n.Type), n.Type, likely) Naddr(&p.From, n) Patch(p, to) @@ -2352,7 +2354,7 @@ func Ginscall(f *Node, proc int) { // into the instruction stream. Thearch.Ginsnop() - if Thearch.Thechar == '9' { + if Thearch.LinkArch.Family == sys.PPC64 { // On ppc64, when compiling Go into position // independent code on ppc64le we insert an // instruction to reload the TOC pointer from the @@ -2630,7 +2632,7 @@ func cgen_div(op Op, nl *Node, nr *Node, res *Node) { // in peep and optoas in order to enable this. // TODO(rsc): ppc64 needs to support the relevant instructions // in peep and optoas in order to enable this. - if nr.Op != OLITERAL || Ctxt.Arch.Thechar == '0' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' { + if nr.Op != OLITERAL || Ctxt.Arch.Family == sys.MIPS64 || Ctxt.Arch.Family == sys.ARM64 || Ctxt.Arch.Family == sys.PPC64 { goto longdiv } w = int(nl.Type.Width * 8) @@ -2995,7 +2997,7 @@ func cgen_slice(n, res *Node, wb bool) { regalloc := Regalloc ginscon := Thearch.Ginscon gins := Thearch.Gins - if Thearch.Thechar == '8' { + if Thearch.LinkArch.Family == sys.I386 { regalloc = func(n *Node, t *Type, reuse *Node) { Tempname(n, t) } @@ -3238,7 +3240,7 @@ func cgen_slice(n, res *Node, wb bool) { compare := func(n1, n2 *Node) { // n1 might be a 64-bit constant, even on 32-bit architectures, // but it will be represented in 32 bits. - if Ctxt.Arch.Regsize == 4 && Is64(n1.Type) { + if Ctxt.Arch.RegSize == 4 && Is64(n1.Type) { if n1.Val().U.(*Mpint).CmpInt64(1<<31) >= 0 { Fatalf("missed slice out of bounds check") } diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go index 4a98f41bcb..7527452c93 100644 --- a/src/cmd/compile/internal/gc/gen.go +++ b/src/cmd/compile/internal/gc/gen.go @@ -8,6 +8,7 @@ package gc import ( "cmd/internal/obj" + "cmd/internal/sys" "fmt" ) @@ -1174,7 +1175,7 @@ func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset i } // NOTE: Assuming little endian (signed top half at offset 4). // We don't have any 32-bit big-endian systems. - if Thearch.Thechar != '5' && Thearch.Thechar != '8' { + if !Thearch.LinkArch.InFamily(sys.ARM, sys.I386) { Fatalf("unknown 32-bit architecture") } return f(Types[TUINT32], startOffset) && diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index 4cb985b1be..ef8b516ea5 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -360,9 +360,8 @@ const ( ) type Arch struct { - Thechar int - Thestring string - Thelinkarch *obj.LinkArch + LinkArch *obj.LinkArch + REGSP int REGCTXT int REGCALLX int // BX diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go index a2fa5f8b31..63a8e969c3 100644 --- a/src/cmd/compile/internal/gc/gsubr.go +++ b/src/cmd/compile/internal/gc/gsubr.go @@ -32,6 +32,7 @@ package gc import ( "cmd/internal/obj" + "cmd/internal/sys" "fmt" "runtime" "strings" @@ -57,7 +58,7 @@ func Ismem(n *Node) bool { return true case OADDR: - return Thearch.Thechar == '6' || Thearch.Thechar == '9' // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too + return Thearch.LinkArch.InFamily(sys.AMD64, sys.PPC64) // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too } return false @@ -83,7 +84,7 @@ func Gbranch(as obj.As, t *Type, likely int) *obj.Prog { p := Prog(as) p.To.Type = obj.TYPE_BRANCH p.To.Val = nil - if as != obj.AJMP && likely != 0 && Thearch.Thechar != '9' && Thearch.Thechar != '7' && Thearch.Thechar != '0' { + if as != obj.AJMP && likely != 0 && Thearch.LinkArch.Family != sys.PPC64 && Thearch.LinkArch.Family != sys.ARM64 && Thearch.LinkArch.Family != sys.MIPS64 { p.From.Type = obj.TYPE_CONST if likely > 0 { p.From.Offset = 1 @@ -330,7 +331,7 @@ func Naddr(a *obj.Addr, n *Node) { a.Type = obj.TYPE_REG a.Reg = n.Reg a.Sym = nil - if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width. + if Thearch.LinkArch.Family == sys.I386 { // TODO(rsc): Never clear a->width. a.Width = 0 } @@ -342,7 +343,7 @@ func Naddr(a *obj.Addr, n *Node) { if a.Offset != int64(int32(a.Offset)) { Yyerror("offset %d too large for OINDREG", a.Offset) } - if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width. + if Thearch.LinkArch.Family == sys.I386 { // TODO(rsc): Never clear a->width. a.Width = 0 } @@ -424,7 +425,7 @@ func Naddr(a *obj.Addr, n *Node) { Naddr(a, n.Left) case OLITERAL: - if Thearch.Thechar == '8' { + if Thearch.LinkArch.Family == sys.I386 { a.Width = 0 } switch n.Val().Ctype() { @@ -457,7 +458,7 @@ func Naddr(a *obj.Addr, n *Node) { case OADDR: Naddr(a, n.Left) a.Etype = uint8(Tptr) - if Thearch.Thechar != '0' && Thearch.Thechar != '5' && Thearch.Thechar != '7' && Thearch.Thechar != '9' { // TODO(rsc): Do this even for arm, ppc64. + if !Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) { // TODO(rsc): Do this even for arm, ppc64. a.Width = int64(Widthptr) } if a.Type != obj.TYPE_MEM { @@ -496,7 +497,7 @@ func Naddr(a *obj.Addr, n *Node) { } a.Etype = uint8(Simtype[TUINT]) a.Offset += int64(Array_nel) - if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm. + if Thearch.LinkArch.Family != sys.ARM { // TODO(rsc): Do this even on arm. a.Width = int64(Widthint) } @@ -509,7 +510,7 @@ func Naddr(a *obj.Addr, n *Node) { } a.Etype = uint8(Simtype[TUINT]) a.Offset += int64(Array_cap) - if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm. + if Thearch.LinkArch.Family != sys.ARM { // TODO(rsc): Do this even on arm. a.Width = int64(Widthint) } } @@ -695,7 +696,7 @@ func Regalloc(n *Node, t *Type, o *Node) { Fatalf("regalloc: t nil") } et := Simtype[t.Etype] - if Ctxt.Arch.Regsize == 4 && (et == TINT64 || et == TUINT64) { + if Ctxt.Arch.RegSize == 4 && (et == TINT64 || et == TUINT64) { Fatalf("regalloc 64bit") } diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 73ecb09fa5..72e6478afe 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -10,6 +10,7 @@ import ( "bufio" "cmd/compile/internal/ssa" "cmd/internal/obj" + "cmd/internal/sys" "flag" "fmt" "io" @@ -96,12 +97,12 @@ func Main() { // but not other values. p := obj.Getgoarch() - if !strings.HasPrefix(p, Thearch.Thestring) { - log.Fatalf("cannot use %cg with GOARCH=%s", Thearch.Thechar, p) + if !strings.HasPrefix(p, Thearch.LinkArch.Name) { + log.Fatalf("cannot use %cg with GOARCH=%s", Thearch.LinkArch.Family, p) } goarch = p - Ctxt = obj.Linknew(Thearch.Thelinkarch) + Ctxt = obj.Linknew(Thearch.LinkArch) Ctxt.DiagFunc = Yyerror Ctxt.Bso = &bstdout bstdout = *obj.Binitw(os.Stdout) @@ -200,15 +201,13 @@ func Main() { obj.Flagcount("y", "debug declarations in canned imports (with -d)", &Debug['y']) var flag_shared int var flag_dynlink bool - switch Thearch.Thechar { - case '5', '6', '7', '8', '9': + if Thearch.LinkArch.InFamily(sys.ARM, sys.AMD64, sys.ARM64, sys.I386, sys.PPC64) { obj.Flagcount("shared", "generate code that can be linked into a shared library", &flag_shared) } - if Thearch.Thechar == '6' { + if Thearch.LinkArch.Family == sys.AMD64 { obj.Flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel) } - switch Thearch.Thechar { - case '5', '6', '7', '8', '9': + if Thearch.LinkArch.InFamily(sys.ARM, sys.AMD64, sys.ARM64, sys.I386, sys.PPC64) { flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries") } obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile) @@ -301,9 +300,9 @@ func Main() { } Thearch.Betypeinit() - if Widthptr == 0 { - Fatalf("betypeinit failed") - } + Widthint = Thearch.LinkArch.IntSize + Widthptr = Thearch.LinkArch.PtrSize + Widthreg = Thearch.LinkArch.RegSize initUniverse() diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go index 63f7bf825e..bfb65ade38 100644 --- a/src/cmd/compile/internal/gc/pgen.go +++ b/src/cmd/compile/internal/gc/pgen.go @@ -7,6 +7,7 @@ package gc import ( "cmd/compile/internal/ssa" "cmd/internal/obj" + "cmd/internal/sys" "crypto/md5" "fmt" "sort" @@ -286,7 +287,7 @@ func allocauto(ptxt *obj.Prog) { if haspointers(n.Type) { stkptrsize = Stksize } - if Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' { + if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) { Stksize = Rnd(Stksize, int64(Widthptr)) } if Stksize >= 1<<31 { @@ -323,7 +324,7 @@ func Cgen_checknil(n *Node) { Fatalf("bad checknil") } - if ((Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL { + if (Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL { var reg Node Regalloc(®, Types[Tptr], n) Cgen(n, ®) diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go index 43f594e2ea..6e43d3133f 100644 --- a/src/cmd/compile/internal/gc/plive.go +++ b/src/cmd/compile/internal/gc/plive.go @@ -17,6 +17,7 @@ package gc import ( "cmd/internal/obj" + "cmd/internal/sys" "fmt" "sort" "strings" @@ -1396,7 +1397,7 @@ func livenessepilogue(lv *Liveness) { // The instruction before a call to deferreturn is always a // no-op, to keep PC-specific data unambiguous. prev := p.Opt.(*obj.Prog) - if Ctxt.Arch.Thechar == '9' { + if Ctxt.Arch.Family == sys.PPC64 { // On ppc64 there is an additional instruction // (another no-op or reload of toc pointer) before // the call. diff --git a/src/cmd/compile/internal/gc/reg.go b/src/cmd/compile/internal/gc/reg.go index 26746a5bcf..8705d6dfa4 100644 --- a/src/cmd/compile/internal/gc/reg.go +++ b/src/cmd/compile/internal/gc/reg.go @@ -33,6 +33,7 @@ package gc import ( "bytes" "cmd/internal/obj" + "cmd/internal/sys" "fmt" "sort" "strings" @@ -249,7 +250,7 @@ func addmove(r *Flow, bn int, rn int, f int) { p1.As = Thearch.Optoas(OAS, Types[uint8(v.etype)]) // TODO(rsc): Remove special case here. - if (Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && v.etype == TBOOL { + if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) && v.etype == TBOOL { p1.As = Thearch.Optoas(OAS, Types[TUINT8]) } p1.From.Type = obj.TYPE_REG @@ -302,7 +303,7 @@ func mkvar(f *Flow, a *obj.Addr) Bits { // TODO(rsc): Remove special case here. case obj.TYPE_ADDR: var bit Bits - if Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' { + if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM, sys.ARM64, sys.PPC64) { goto memcase } a.Type = obj.TYPE_MEM @@ -368,7 +369,7 @@ func mkvar(f *Flow, a *obj.Addr) Bits { if v.etype == et { if int64(v.width) == w { // TODO(rsc): Remove special case for arm here. - if flag == 0 || Thearch.Thechar != '5' { + if flag == 0 || Thearch.LinkArch.Family != sys.ARM { return blsh(uint(i)) } } diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 127a7c4698..90c4d4e95e 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -13,6 +13,7 @@ import ( "cmd/compile/internal/ssa" "cmd/internal/obj" + "cmd/internal/sys" ) var ssaEnabled = true @@ -24,13 +25,13 @@ func initssa() *ssa.Config { ssaExp.unimplemented = false ssaExp.mustImplement = true if ssaConfig == nil { - ssaConfig = ssa.NewConfig(Thearch.Thestring, &ssaExp, Ctxt, Debug['N'] == 0) + ssaConfig = ssa.NewConfig(Thearch.LinkArch.Name, &ssaExp, Ctxt, Debug['N'] == 0) } return ssaConfig } func shouldssa(fn *Node) bool { - switch Thearch.Thestring { + switch Thearch.LinkArch.Name { default: // Only available for testing. if os.Getenv("SSATEST") == "" { @@ -2409,7 +2410,7 @@ func isSSAIntrinsic1(s *Sym) bool { // so far has only been noticed for Bswap32 and the 16-bit count // leading/trailing instructions, but heuristics might change // in the future or on different architectures). - if !ssaEnabled || ssa.IntrinsicsDisable || Thearch.Thechar != '6' { + if !ssaEnabled || ssa.IntrinsicsDisable || Thearch.LinkArch.Family != sys.AMD64 { return false } if s != nil && s.Pkg != nil && s.Pkg.Path == "runtime/internal/sys" { diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index ff8ddea7f6..586a8e9c4f 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -6,6 +6,7 @@ package gc import ( "cmd/internal/obj" + "cmd/internal/sys" "fmt" "strings" ) @@ -672,8 +673,7 @@ opswitch: walkexprlist(n.List.Slice(), init) if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" { - switch Thearch.Thechar { - case '5', '6', '7', '9': + if Thearch.LinkArch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.PPC64) { n.Op = OSQRT n.Left = n.List.First() n.List.Set(nil) @@ -1056,7 +1056,7 @@ opswitch: n = walkexpr(n, init) case OCONV, OCONVNOP: - if Thearch.Thechar == '5' { + if Thearch.LinkArch.Family == sys.ARM { if n.Left.Type.IsFloat() { if n.Type.Etype == TINT64 { n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64])) @@ -3274,7 +3274,7 @@ func samecheap(a *Node, b *Node) bool { // The result of walkrotate MUST be assigned back to n, e.g. // n.Left = walkrotate(n.Left) func walkrotate(n *Node) *Node { - if Thearch.Thechar == '0' || Thearch.Thechar == '7' || Thearch.Thechar == '9' { + if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) { return n } @@ -3401,7 +3401,7 @@ func walkdiv(n *Node, init *Nodes) *Node { // if >= 0, nr is 1<= 32678 { ld.Diag("TLS offset out of range %d", v) } 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/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 6bbd6c7d5c..ae430b4e45 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -34,6 +34,7 @@ package ld import ( "cmd/internal/gcprog" "cmd/internal/obj" + "cmd/internal/sys" "fmt" "log" "os" @@ -121,7 +122,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 { @@ -138,12 +139,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) @@ -163,7 +164,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) @@ -178,15 +179,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) @@ -202,12 +203,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) } @@ -356,7 +357,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) } } @@ -365,7 +366,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 @@ -394,7 +395,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 @@ -404,13 +405,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). @@ -428,7 +429,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 @@ -438,7 +439,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 @@ -465,7 +466,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 { @@ -475,10 +476,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) } } @@ -498,7 +499,7 @@ 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() } @@ -515,7 +516,7 @@ func relocsym(s *LSym) { r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) o = r.Xadd rs = r.Xsym - if Iself && Thearch.Thechar == '6' { + if Iself && SysArch.Family == sys.AMD64 { o = 0 } break @@ -544,7 +545,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 { @@ -556,7 +557,7 @@ func relocsym(s *LSym) { } 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) @@ -675,7 +676,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) @@ -982,7 +983,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 @@ -1128,7 +1129,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") @@ -1144,7 +1145,7 @@ func (p *GCProg) AddSym(s *LSym) { return } - ptrsize := int64(Thearch.Ptrsize) + ptrsize := int64(SysArch.PtrSize) nptr := decodetype_ptrdata(typ) / ptrsize if debugGCProg { @@ -1532,7 +1533,7 @@ func dodata() { if s != nil && s.Type == obj.STLSBSS { 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 diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index 56c4370bcc..b17b96001e 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" @@ -227,7 +228,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") diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index 0a6bf094aa..bc29938590 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" ) @@ -46,39 +47,39 @@ 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 6*SysArch.PtrSize + 8 } // runtime._type +func structfieldSize() int { return 3 * SysArch.PtrSize } // runtime.structfield +func uncommonSize() int { return 2*SysArch.PtrSize + 2*SysArch.IntSize } // runtime.uncommontype // Type.commonType.kind func decodetype_kind(s *LSym) uint8 { - return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindMask) // 0x13 / 0x1f + return uint8(s.P[2*SysArch.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 uint8(s.P[2*SysArch.PtrSize+7] & obj.KindNoPointers) // 0x13 / 0x1f } // Type.commonType.kind func decodetype_usegcprog(s *LSym) uint8 { - return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindGCProg) // 0x13 / 0x1f + return uint8(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 +113,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 +125,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 +134,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 +151,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 +165,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 +189,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 +204,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() } @@ -224,7 +225,7 @@ func decodetype_stringptr(s *LSym, off int) string { if r == nil { // shouldn't happen. return "" } - strlen := int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Intsize)) + strlen := int64(decode_inuxi(s.P[SysArch.PtrSize:], SysArch.IntSize)) return string(r.Sym.P[r.Add : r.Add+strlen]) } @@ -248,17 +249,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 @@ -288,7 +289,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+SysArch.PtrSize)) buf.WriteRune('(') inCount := decodetype_funcincount(mtypSym) @@ -319,7 +320,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 +329,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 := 2 * SysArch.PtrSize return decode_methodsig(s, off, sizeofIMethod, numMethods) } @@ -339,31 +340,31 @@ 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)) + numMethods := int(decode_inuxi(s.P[off+2*SysArch.PtrSize:], SysArch.IntSize)) + r := decode_reloc(s, int32(off+SysArch.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 + sizeofMethod := 4 * SysArch.PtrSize // sizeof reflect.method in program return decode_methodsig(s, off, sizeofMethod, numMethods) } diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index eaa0bdbb41..230d146877 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -39,7 +39,7 @@ var gdbscript string * Basic I/O */ func addrput(s *LSym, addr int64) { - switch Thearch.Ptrsize { + switch SysArch.PtrSize { case 4: Adduint32(Ctxt, s, uint32(addr)) @@ -569,7 +569,7 @@ func adddwarfref(ctxt *Link, s *LSym, t *LSym, size int) int64 { default: Diag("invalid size %d in adddwarfref\n", size) fallthrough - case Thearch.Ptrsize: + case SysArch.PtrSize: result = Addaddr(ctxt, s, t) case 4: result = addaddrplus4(ctxt, s, t, 0) @@ -599,7 +599,7 @@ func putattr(s *LSym, abbrev int, form int, cls int, value int64, data interface case DW_FORM_block1: // block if cls == DW_CLS_ADDRESS { - Adduint8(Ctxt, s, uint8(1+Thearch.Ptrsize)) + Adduint8(Ctxt, s, uint8(1+SysArch.PtrSize)) Adduint8(Ctxt, s, DW_OP_addr) Addaddr(Ctxt, s, data.(*LSym)) break @@ -682,14 +682,14 @@ func putattr(s *LSym, 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 { + if SysArch.PtrSize == 8 { Adduint64(Ctxt, s, 0) // invalid dwarf, gdb will complain. } else { Adduint32(Ctxt, s, 0) // invalid dwarf, gdb will complain. } } else { dsym := data.(*LSym) - adddwarfref(Ctxt, s, dsym, Thearch.Ptrsize) + adddwarfref(Ctxt, s, dsym, SysArch.PtrSize) } case DW_FORM_ref1, // reference within the compilation unit @@ -1161,11 +1161,11 @@ func synthesizemaptypes(die *DWDie) { // compute size info like hashmap.c does. indirect_key, indirect_val := false, false if keysize > MaxKeySize { - keysize = int64(Thearch.Ptrsize) + keysize = int64(SysArch.PtrSize) indirect_key = true } if valsize > MaxValSize { - valsize = int64(Thearch.Ptrsize) + valsize = int64(SysArch.PtrSize) indirect_val = true } @@ -1212,13 +1212,13 @@ func synthesizemaptypes(die *DWDie) { 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 Thearch.Regsize > Thearch.Ptrsize { + 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(Thearch.Ptrsize)) + 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*int64(keysize)+BucketSize*int64(valsize)+int64(SysArch.RegSize), 0) }) // Construct hash @@ -1481,7 +1481,7 @@ func writelines(prev *LSym) *LSym { headerend = ls.Size Adduint8(Ctxt, ls, 0) // start extended opcode - uleb128put(ls, 1+int64(Thearch.Ptrsize)) + uleb128put(ls, 1+int64(SysArch.PtrSize)) Adduint8(Ctxt, ls, DW_LNE_set_address) pc := s.Value @@ -1555,7 +1555,7 @@ func writelines(prev *LSym) *LSym { dt = DW_ABRV_AUTO offs = int64(a.Aoffset) if !haslinkregister() { - offs -= int64(Thearch.Ptrsize) + offs -= int64(SysArch.PtrSize) } case obj.A_PARAM: @@ -1667,7 +1667,7 @@ func writeframes(prev *LSym) *LSym { if haslinkregister() { uleb128put(fs, int64(0)) // offset } else { - uleb128put(fs, int64(Thearch.Ptrsize)) // offset + uleb128put(fs, int64(SysArch.PtrSize)) // offset } Adduint8(Ctxt, fs, DW_CFA_offset_extended) @@ -1675,7 +1675,7 @@ func writeframes(prev *LSym) *LSym { if haslinkregister() { uleb128put(fs, int64(0)/DATAALIGNMENTFACTOR) // at cfa - 0 } else { - uleb128put(fs, int64(-Thearch.Ptrsize)/DATAALIGNMENTFACTOR) // at cfa - x*4 + uleb128put(fs, int64(-SysArch.PtrSize)/DATAALIGNMENTFACTOR) // at cfa - x*4 } // 4 is to exclude the length field. @@ -1713,10 +1713,10 @@ func writeframes(prev *LSym) *LSym { if haslinkregister() { 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. @@ -1724,7 +1724,7 @@ func writeframes(prev *LSym) *LSym { // 4 bytes: Pointer to the CIE above, at offset 0 // ptrsize: initial location // ptrsize: address range - Adduint32(Ctxt, fs, 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 { adddwarfref(Ctxt, fs, framesec, 4) } else { @@ -1771,7 +1771,7 @@ func writeinfo(prev *LSym) *LSym { // debug_abbrev_offset (*) adddwarfref(Ctxt, s, abbrevsym, 4) - Adduint8(Ctxt, s, uint8(Thearch.Ptrsize)) // address_size + Adduint8(Ctxt, s, uint8(SysArch.PtrSize)) // address_size prev = putdie(prev, compunit) cusize := s.Size - 4 // exclude the length field. @@ -1848,7 +1848,7 @@ func writearanges(prev *LSym) *LSym { 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) @@ -1861,13 +1861,13 @@ func writearanges(prev *LSym) *LSym { } // Write .debug_aranges Header + entry (sec 6.1.2) - unitlength := uint32(headersize) + 4*uint32(Thearch.Ptrsize) - 4 + unitlength := uint32(headersize) + 4*uint32(SysArch.PtrSize) - 4 Adduint32(Ctxt, s, unitlength) // unit_length (*) Adduint16(Ctxt, s, 2) // dwarf version (appendix F) adddwarfref(Ctxt, s, compunit.sym, 4) - Adduint8(Ctxt, s, uint8(Thearch.Ptrsize)) // address_size + 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++ { @@ -1940,7 +1940,7 @@ func dwarfgeneratedebugsyms() { 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. diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 035826df7c..7c760775b5 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++ { @@ -1660,15 +1658,15 @@ 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 } @@ -1872,7 +1870,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") @@ -1919,7 +1917,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 @@ -1938,7 +1936,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 @@ -1993,15 +1991,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) } @@ -2080,22 +2078,22 @@ func Asmbelfsetup() { 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 } @@ -2251,7 +2249,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) @@ -2275,7 +2273,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)) @@ -2286,7 +2284,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)) @@ -2350,15 +2348,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)) } @@ -2366,7 +2364,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)) @@ -2375,8 +2373,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() @@ -2402,7 +2400,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) } } } @@ -2411,12 +2409,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: @@ -2476,8 +2474,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) @@ -2600,7 +2598,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 { @@ -2628,9 +2626,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/ldelf.go b/src/cmd/link/internal/ld/ldelf.go index 0255331ac6..3aee2d5ece 100644 --- a/src/cmd/link/internal/ld/ldelf.go +++ b/src/cmd/link/internal/ld/ldelf.go @@ -3,6 +3,7 @@ package ld import ( "bytes" "cmd/internal/obj" + "cmd/internal/sys" "encoding/binary" "fmt" "io" @@ -546,47 +547,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 @@ -1056,7 +1058,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 @@ -1127,7 +1129,9 @@ func (x rbyoff) Less(i, j int) bool { } func reltype(pn string, elftype int, siz *uint8) int { - switch uint32(Thearch.Thechar) | uint32(elftype)<<24 { + // TODO(mdempsky): Remove dependency on ArchFamily char values. + + switch uint32(SysArch.Family) | uint32(elftype)<<24 { default: Diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype) fallthrough diff --git a/src/cmd/link/internal/ld/ldmacho.go b/src/cmd/link/internal/ld/ldmacho.go index c4c13f13b9..9fbb2123af 100644 --- a/src/cmd/link/internal/ld/ldmacho.go +++ b/src/cmd/link/internal/ld/ldmacho.go @@ -2,6 +2,7 @@ package ld import ( "cmd/internal/obj" + "cmd/internal/sys" "encoding/binary" "fmt" "log" @@ -471,18 +472,18 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) { 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 @@ -724,10 +725,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 +821,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 +847,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 +866,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..ea0c482838 100644 --- a/src/cmd/link/internal/ld/ldpe.go +++ b/src/cmd/link/internal/ld/ldpe.go @@ -6,6 +6,7 @@ package ld import ( "cmd/internal/obj" + "cmd/internal/sys" "encoding/binary" "fmt" "log" @@ -492,7 +493,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..3e0bd8ebc4 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -34,6 +34,7 @@ import ( "bufio" "bytes" "cmd/internal/obj" + "cmd/internal/sys" "crypto/sha1" "debug/elf" "encoding/binary" @@ -82,14 +83,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 @@ -191,8 +187,7 @@ func UseRelro() bool { } var ( - Thestring string - Thelinkarch *LinkArch + SysArch *sys.Arch outfile string dynexp []*LSym dynlib []string @@ -509,7 +504,7 @@ func loadlib() { } loadinternal("runtime") - if Thearch.Thechar == '5' { + if SysArch.Family == sys.ARM { loadinternal("math") } if flag_race != 0 { @@ -562,7 +557,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 +616,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 +634,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 @@ -1226,7 +1221,7 @@ func hostlink() { 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 +1249,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 @@ -1306,10 +1301,10 @@ func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, when 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("%cl: input %s is not .%c file (use %cg to compile .go files)", SysArch.Family, pn, SysArch.Family, SysArch.Family) } - if line == Thestring { + if line == SysArch.Name { // old header format: just $GOOS Diag("%s: stale object file", pn) return nil @@ -1500,12 +1495,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 @@ -1565,8 +1560,8 @@ func mywhatsys() { goos = obj.Getgoos() goarch = obj.Getgoarch() - if !strings.HasPrefix(goarch, Thestring) { - log.Fatalf("cannot use %cc with GOARCH=%s", Thearch.Thechar, goarch) + if !strings.HasPrefix(goarch, SysArch.Name) { + log.Fatalf("cannot use %cc with GOARCH=%s", SysArch.Family, goarch) } } @@ -1608,7 +1603,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 +1647,7 @@ func callsize() int { if haslinkregister() { return 0 } - return Thearch.Regsize + return SysArch.RegSize } func dostkcheck() { @@ -1986,7 +1981,7 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) { put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), s.Gotype) // 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(s.Locals)+int64(SysArch.PtrSize), 0, 0, nil) for _, a := range s.Autom { // Emit a or p according to actual offset, even if label is wrong. @@ -1999,7 +1994,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 +2004,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 } } diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index 67a855933e..f0811389d2 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -32,8 +32,8 @@ package ld import ( "cmd/internal/obj" + "cmd/internal/sys" "debug/elf" - "encoding/binary" "fmt" ) @@ -161,11 +161,9 @@ type Shlib struct { } type Link struct { - Thechar int32 - Thestring string Goarm int32 Headtype int - Arch *LinkArch + Arch *sys.Arch Debugvlog int32 Bso *obj.Biobuf Windows int32 @@ -196,15 +194,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 +211,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 diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index cafc6b0382..25d48fbf22 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" ) @@ -131,15 +132,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,8 +349,8 @@ func machoshbits(mseg *MachoSeg, sect *Section, segname string) { buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1) var msect *MachoSect - if sect.Rwx&1 == 0 && segname != "__DWARF" && (Thearch.Thechar == '7' || // arm64 - (Thearch.Thechar == '6' && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive))) { // amd64 + if sect.Rwx&1 == 0 && segname != "__DWARF" && (SysArch.Family == sys.ARM64 || + (SysArch.Family == sys.AMD64 && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive))) { // Darwin external linker on arm64 and on amd64 in c-shared/c-archive buildmode // complains about absolute relocs in __TEXT, so if the section is not // executable, put it in __DATA segment. @@ -422,23 +415,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 } @@ -449,7 +442,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 @@ -511,31 +504,31 @@ func Asmbmacho() { } 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 */ @@ -546,7 +539,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) @@ -729,7 +721,7 @@ func machosymtab() { 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) @@ -747,7 +739,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) } } } diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index ff29ce2d70..471dda712f 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) } @@ -242,12 +242,12 @@ func pclntab() { } 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 @@ -272,16 +272,16 @@ func pclntab() { } funcstart = int32(len(ftab.P)) - funcstart += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1) + 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 - 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)) @@ -330,25 +330,25 @@ func pclntab() { // 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++ { 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,14 +357,14 @@ 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)) diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index 56698361d0..0204b8c8c2 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) } } @@ -946,7 +947,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 +1003,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) } } @@ -1129,12 +1130,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..b9902a5e5e 100644 --- a/src/cmd/link/internal/ld/pobj.go +++ b/src/cmd/link/internal/ld/pobj.go @@ -32,6 +32,7 @@ package ld import ( "cmd/internal/obj" + "cmd/internal/sys" "flag" "fmt" "os" @@ -44,9 +45,7 @@ var ( ) func Ldmain() { - Ctxt = linknew(Thelinkarch) - Ctxt.Thechar = int32(Thearch.Thechar) - Ctxt.Thestring = Thestring + Ctxt = linknew(SysArch) Ctxt.Diag = Diag Ctxt.Bso = &Bso @@ -70,7 +69,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) @@ -107,7 +106,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) 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 167176cc2d..ecd5c741bb 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" @@ -160,7 +161,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. @@ -229,7 +230,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 } diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go index d0977e9b00..9a145e373a 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" @@ -82,8 +83,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 +100,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 } @@ -214,7 +215,7 @@ 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 */ 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/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/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 7da5dd02be..91251de15e 100644 --- a/src/cmd/link/internal/x86/asm.go +++ b/src/cmd/link/internal/x86/asm.go @@ -292,7 +292,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 +317,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 } 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 -- cgit v1.3-5-g9baa From d481ffc1afeae8852caa3452a0e23b1cd90d1e10 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 6 Apr 2016 18:54:17 -0700 Subject: cmd/compile, cmd/link: eliminate uses of ArchFamily in error messages Two of these error messages are already dead code: cmd/compile.main and cmd/link.main already switch on $GOARCH, ensuring it must be a prefix of the sys.Arch.Family. The error message about uncompiled Go source files can be just be simplified: anyone who's manually constructing Go object file archives probably knows what tool to use to compile Go source files. Change-Id: Ia4a67c0a1d1158379c127c91e909226d3367f3c2 Reviewed-on: https://go-review.googlesource.com/21626 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/cmd/compile/internal/gc/main.go | 9 +-------- src/cmd/link/internal/ld/lib.go | 7 ++----- 2 files changed, 3 insertions(+), 13 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 72e6478afe..079f4916c7 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -93,14 +93,7 @@ func doversion() { func Main() { defer hidePanic() - // Allow GOARCH=thearch.thestring or GOARCH=thearch.thestringsuffix, - // but not other values. - p := obj.Getgoarch() - - if !strings.HasPrefix(p, Thearch.LinkArch.Name) { - log.Fatalf("cannot use %cg with GOARCH=%s", Thearch.LinkArch.Family, p) - } - goarch = p + goarch = obj.Getgoarch() Ctxt = obj.Linknew(Thearch.LinkArch) Ctxt.DiagFunc = Yyerror diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 3e0bd8ebc4..305a3bc0db 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1301,7 +1301,8 @@ func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, when 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)", SysArch.Family, pn, SysArch.Family, SysArch.Family) + Exitf("%s: uncompiled .go source file", pn) + return nil } if line == SysArch.Name { @@ -1559,10 +1560,6 @@ func mywhatsys() { goroot = obj.Getgoroot() goos = obj.Getgoos() goarch = obj.Getgoarch() - - if !strings.HasPrefix(goarch, SysArch.Name) { - log.Fatalf("cannot use %cc with GOARCH=%s", SysArch.Family, goarch) - } } // Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync. -- cgit v1.3-5-g9baa From 22ef687da815c4d651cef3c1b7d44f41100b6715 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 6 Apr 2016 20:06:12 -0700 Subject: cmd/link: remove dependency on sys.ArchFamily values Change-Id: I858054b72847f4f27a1ebbdaff82820a28c03743 Reviewed-on: https://go-review.googlesource.com/21627 Reviewed-by: Brad Fitzpatrick --- src/cmd/link/internal/ld/ldelf.go | 153 ++++++++++++++++++++------------------ 1 file changed, 81 insertions(+), 72 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go index 3aee2d5ece..485599be62 100644 --- a/src/cmd/link/internal/ld/ldelf.go +++ b/src/cmd/link/internal/ld/ldelf.go @@ -927,7 +927,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 { @@ -1128,81 +1129,89 @@ func (x rbyoff) Less(i, j int) bool { return false } -func reltype(pn string, elftype int, siz *uint8) int { - // TODO(mdempsky): Remove dependency on ArchFamily char values. +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. - switch uint32(SysArch.Family) | uint32(elftype)<<24 { + 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 '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 '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 '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 S390X | R_390_8<<24: + return 1 + + 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 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 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 } -- cgit v1.3-5-g9baa From 4b7e36cdfe8e0c3579a2503a81474fe43db4db69 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 6 Apr 2016 21:45:29 -0700 Subject: cmd: extract obj's Biobuf code into new bio package API could still be made more Go-ey. Updates #15165. Change-Id: I514ffceffa43c293ae5d7e5f1e9193fda0098865 Reviewed-on: https://go-review.googlesource.com/21644 Reviewed-by: Brad Fitzpatrick Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot --- src/cmd/asm/internal/asm/endtoend_test.go | 5 +- src/cmd/asm/main.go | 5 +- src/cmd/compile/internal/gc/bexport.go | 10 +- src/cmd/compile/internal/gc/export.go | 8 +- src/cmd/compile/internal/gc/go.go | 5 +- src/cmd/compile/internal/gc/main.go | 5 +- src/cmd/compile/internal/gc/obj.go | 31 +++--- src/cmd/dist/buildtool.go | 1 + src/cmd/internal/bio/buf.go | 150 ++++++++++++++++++++++++++++++ src/cmd/internal/obj/link.go | 7 +- src/cmd/internal/obj/objfile.go | 9 +- src/cmd/internal/obj/util.go | 140 ---------------------------- src/cmd/link/internal/ld/ar.go | 15 +-- src/cmd/link/internal/ld/go.go | 5 +- src/cmd/link/internal/ld/ldelf.go | 13 +-- src/cmd/link/internal/ld/ldmacho.go | 23 ++--- src/cmd/link/internal/ld/ldpe.go | 27 +++--- src/cmd/link/internal/ld/lib.go | 83 ++++++++--------- src/cmd/link/internal/ld/link.go | 4 +- src/cmd/link/internal/ld/objfile.go | 9 +- src/cmd/link/internal/ld/pobj.go | 3 +- 21 files changed, 291 insertions(+), 267 deletions(-) create mode 100644 src/cmd/internal/bio/buf.go (limited to 'src/cmd/link') diff --git a/src/cmd/asm/internal/asm/endtoend_test.go b/src/cmd/asm/internal/asm/endtoend_test.go index 1307c4243f..8986281f10 100644 --- a/src/cmd/asm/internal/asm/endtoend_test.go +++ b/src/cmd/asm/internal/asm/endtoend_test.go @@ -17,6 +17,7 @@ import ( "testing" "cmd/asm/internal/lex" + "cmd/internal/bio" "cmd/internal/obj" ) @@ -33,7 +34,7 @@ func testEndToEnd(t *testing.T, goarch, file string) { pList := obj.Linknewplist(ctxt) var ok bool testOut = new(bytes.Buffer) // The assembler writes test output to this buffer. - ctxt.Bso = obj.Binitw(os.Stdout) + ctxt.Bso = bio.BufWriter(os.Stdout) defer ctxt.Bso.Flush() failed := false ctxt.DiagFunc = func(format string, args ...interface{}) { @@ -271,7 +272,7 @@ func testErrors(t *testing.T, goarch, file string) { pList := obj.Linknewplist(ctxt) var ok bool testOut = new(bytes.Buffer) // The assembler writes test output to this buffer. - ctxt.Bso = obj.Binitw(os.Stdout) + ctxt.Bso = bio.BufWriter(os.Stdout) defer ctxt.Bso.Flush() failed := false var errBuf bytes.Buffer diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go index 4e450bec98..75cb8f75d3 100644 --- a/src/cmd/asm/main.go +++ b/src/cmd/asm/main.go @@ -15,6 +15,7 @@ import ( "cmd/asm/internal/flags" "cmd/asm/internal/lex" + "cmd/internal/bio" "cmd/internal/obj" ) @@ -45,9 +46,9 @@ func main() { if *flags.Shared || *flags.Dynlink { ctxt.Flag_shared = 1 } - ctxt.Bso = obj.Binitw(os.Stdout) + ctxt.Bso = bio.BufWriter(os.Stdout) defer ctxt.Bso.Flush() - output := obj.Binitw(fd) + output := bio.BufWriter(fd) fmt.Fprintf(output, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion()) fmt.Fprintf(output, "!\n") diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index 092cdac2f6..702090280f 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -92,7 +92,7 @@ package gc import ( "bytes" "cmd/compile/internal/big" - "cmd/internal/obj" + "cmd/internal/bio" "encoding/binary" "fmt" "sort" @@ -124,7 +124,7 @@ const exportVersion = "v0" const exportInlined = true // default: true type exporter struct { - out *obj.Biobuf + out *bio.Buf pkgIndex map[*Pkg]int typIndex map[*Type]int inlined []*Func @@ -136,7 +136,7 @@ type exporter struct { } // Export writes the exportlist for localpkg to out and returns the number of bytes written. -func Export(out *obj.Biobuf, trace bool) int { +func Export(out *bio.Buf, trace bool) int { p := exporter{ out: out, pkgIndex: make(map[*Pkg]int), @@ -1531,10 +1531,10 @@ func (p *exporter) byte(b byte) { fallthrough case '|': // write '|' as '|' '|' - obj.Bputc(p.out, '|') + p.out.WriteByte('|') p.written++ } - obj.Bputc(p.out, b) + p.out.WriteByte(b) p.written++ } diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go index 17311cf6af..5d4add8ff4 100644 --- a/src/cmd/compile/internal/gc/export.go +++ b/src/cmd/compile/internal/gc/export.go @@ -7,7 +7,7 @@ package gc import ( "bufio" "bytes" - "cmd/internal/obj" + "cmd/internal/bio" "fmt" "sort" "unicode" @@ -384,7 +384,7 @@ func dumpexport() { if debugFormat { // save a copy of the export data var copy bytes.Buffer - bcopy := obj.Binitw(©) + bcopy := bio.BufWriter(©) size = Export(bcopy, Debug_export != 0) bcopy.Flush() // flushing to bytes.Buffer cannot fail if n, err := bout.Write(copy.Bytes()); n != size || err != nil { @@ -577,7 +577,7 @@ func importtype(pt *Type, t *Type) { } func dumpasmhdr() { - b, err := obj.Bopenw(asmhdr) + b, err := bio.Create(asmhdr) if err != nil { Fatalf("%v", err) } @@ -604,5 +604,5 @@ func dumpasmhdr() { } } - obj.Bterm(b) + b.Close() } diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index ef8b516ea5..cd9db38fb4 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -6,6 +6,7 @@ package gc import ( "cmd/compile/internal/ssa" + "cmd/internal/bio" "cmd/internal/obj" ) @@ -132,7 +133,7 @@ var infile string var outfile string -var bout *obj.Biobuf +var bout *bio.Buf var nerrors int @@ -287,7 +288,7 @@ var Ctxt *obj.Link var writearchive int -var bstdout obj.Biobuf +var bstdout *bio.Buf var Nacl bool diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 079f4916c7..c8a778c34a 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -9,6 +9,7 @@ package gc import ( "bufio" "cmd/compile/internal/ssa" + "cmd/internal/bio" "cmd/internal/obj" "cmd/internal/sys" "flag" @@ -97,8 +98,8 @@ func Main() { Ctxt = obj.Linknew(Thearch.LinkArch) Ctxt.DiagFunc = Yyerror - Ctxt.Bso = &bstdout - bstdout = *obj.Binitw(os.Stdout) + bstdout = bio.BufWriter(os.Stdout) + Ctxt.Bso = bstdout localpkg = mkpkg("") localpkg.Prefix = "\"\"" diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index 99eb73bd94..3920e25224 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -5,6 +5,7 @@ package gc import ( + "cmd/internal/bio" "cmd/internal/obj" "crypto/sha256" "fmt" @@ -23,7 +24,7 @@ func formathdr(arhdr []byte, name string, size int64) { func dumpobj() { var err error - bout, err = obj.Bopenw(outfile) + bout, err = bio.Create(outfile) if err != nil { Flusherrors() fmt.Printf("can't create %s: %v\n", outfile, err) @@ -33,10 +34,10 @@ func dumpobj() { startobj := int64(0) var arhdr [ArhdrSize]byte if writearchive != 0 { - obj.Bwritestring(bout, "!\n") + bout.WriteString("!\n") arhdr = [ArhdrSize]byte{} bout.Write(arhdr[:]) - startobj = obj.Boffset(bout) + startobj = bio.Boffset(bout) } fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring()) @@ -44,19 +45,19 @@ func dumpobj() { if writearchive != 0 { bout.Flush() - size := obj.Boffset(bout) - startobj + size := bio.Boffset(bout) - startobj if size&1 != 0 { - obj.Bputc(bout, 0) + bout.WriteByte(0) } - obj.Bseek(bout, startobj-ArhdrSize, 0) + bio.Bseek(bout, startobj-ArhdrSize, 0) formathdr(arhdr[:], "__.PKGDEF", size) bout.Write(arhdr[:]) bout.Flush() - obj.Bseek(bout, startobj+size+(size&1), 0) + bio.Bseek(bout, startobj+size+(size&1), 0) arhdr = [ArhdrSize]byte{} bout.Write(arhdr[:]) - startobj = obj.Boffset(bout) + startobj = bio.Boffset(bout) fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring()) } @@ -91,16 +92,16 @@ func dumpobj() { if writearchive != 0 { bout.Flush() - size := obj.Boffset(bout) - startobj + size := bio.Boffset(bout) - startobj if size&1 != 0 { - obj.Bputc(bout, 0) + bout.WriteByte(0) } - obj.Bseek(bout, startobj-ArhdrSize, 0) + bio.Bseek(bout, startobj-ArhdrSize, 0) formathdr(arhdr[:], "_go_.o", size) bout.Write(arhdr[:]) } - obj.Bterm(bout) + bout.Close() } func dumpglobls() { @@ -132,9 +133,9 @@ func dumpglobls() { funcsyms = nil } -func Bputname(b *obj.Biobuf, s *obj.LSym) { - obj.Bwritestring(b, s.Name) - obj.Bputc(b, 0) +func Bputname(b *bio.Buf, s *obj.LSym) { + b.WriteString(s.Name) + b.WriteByte(0) } func Linksym(s *Sym) *obj.LSym { diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go index 123d5ccf82..777c92c726 100644 --- a/src/cmd/dist/buildtool.go +++ b/src/cmd/dist/buildtool.go @@ -38,6 +38,7 @@ var bootstrapDirs = []string{ "compile/internal/ppc64", "compile/internal/ssa", "compile/internal/x86", + "internal/bio", "internal/gcprog", "internal/obj", "internal/obj/arm", diff --git a/src/cmd/internal/bio/buf.go b/src/cmd/internal/bio/buf.go new file mode 100644 index 0000000000..a1df26ca9c --- /dev/null +++ b/src/cmd/internal/bio/buf.go @@ -0,0 +1,150 @@ +// 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 bio implements seekable buffered I/O. +package bio + +import ( + "bufio" + "io" + "log" + "os" +) + +const EOF = -1 + +// Buf implements a seekable buffered I/O abstraction. +type Buf struct { + f *os.File + r *bufio.Reader + w *bufio.Writer +} + +func (b *Buf) Reader() *bufio.Reader { return b.r } +func (b *Buf) Writer() *bufio.Writer { return b.w } + +func Create(name string) (*Buf, error) { + f, err := os.Create(name) + if err != nil { + return nil, err + } + return &Buf{f: f, w: bufio.NewWriter(f)}, nil +} + +func Open(name string) (*Buf, error) { + f, err := os.Open(name) + if err != nil { + return nil, err + } + return &Buf{f: f, r: bufio.NewReader(f)}, nil +} + +func BufWriter(w io.Writer) *Buf { + return &Buf{w: bufio.NewWriter(w)} +} + +func BufReader(r io.Reader) *Buf { + return &Buf{r: bufio.NewReader(r)} +} + +func (b *Buf) Write(p []byte) (int, error) { + return b.w.Write(p) +} + +func (b *Buf) WriteString(p string) (int, error) { + return b.w.WriteString(p) +} + +func Bseek(b *Buf, offset int64, whence int) int64 { + if b.w != nil { + if err := b.w.Flush(); err != nil { + log.Fatalf("writing output: %v", err) + } + } else if b.r != nil { + if whence == 1 { + offset -= int64(b.r.Buffered()) + } + } + off, err := b.f.Seek(offset, whence) + if err != nil { + log.Fatalf("seeking in output: %v", err) + } + if b.r != nil { + b.r.Reset(b.f) + } + return off +} + +func Boffset(b *Buf) int64 { + if b.w != nil { + if err := b.w.Flush(); err != nil { + log.Fatalf("writing output: %v", err) + } + } + off, err := b.f.Seek(0, 1) + if err != nil { + log.Fatalf("seeking in output [0, 1]: %v", err) + } + if b.r != nil { + off -= int64(b.r.Buffered()) + } + return off +} + +func (b *Buf) Flush() error { + return b.w.Flush() +} + +func (b *Buf) WriteByte(c byte) error { + return b.w.WriteByte(c) +} + +func Bread(b *Buf, p []byte) int { + n, err := io.ReadFull(b.r, p) + if n == 0 { + if err != nil && err != io.EOF { + n = -1 + } + } + return n +} + +func Bgetc(b *Buf) int { + c, err := b.r.ReadByte() + if err != nil { + if err != io.EOF { + log.Fatalf("reading input: %v", err) + } + return EOF + } + return int(c) +} + +func (b *Buf) Read(p []byte) (int, error) { + return b.r.Read(p) +} + +func (b *Buf) Peek(n int) ([]byte, error) { + return b.r.Peek(n) +} + +func Brdline(b *Buf, delim int) string { + s, err := b.r.ReadBytes(byte(delim)) + if err != nil { + log.Fatalf("reading input: %v", err) + } + return string(s) +} + +func (b *Buf) Close() error { + var err error + if b.w != nil { + err = b.w.Flush() + } + err1 := b.f.Close() + if err == nil { + err = err1 + } + return err +} diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 81a5689aef..2c81ca2f08 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -30,7 +30,10 @@ package obj -import "cmd/internal/sys" +import ( + "cmd/internal/bio" + "cmd/internal/sys" +) // An Addr is an argument to an instruction. // The general forms and their encodings are: @@ -626,7 +629,7 @@ type Link struct { Flag_shared int32 Flag_dynlink bool Flag_optimize bool - Bso *Biobuf + Bso *bio.Buf Pathname string Goroot string Goroot_final string diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index bdd3bfc826..405cbf446a 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -109,6 +109,7 @@ package obj import ( "bufio" + "cmd/internal/bio" "cmd/internal/sys" "fmt" "log" @@ -120,7 +121,7 @@ import ( // The Go and C compilers, and the assembler, call writeobj to write // out a Go object file. The linker does not call this; the linker // does not write out object files. -func Writeobjdirect(ctxt *Link, b *Biobuf) { +func Writeobjdirect(ctxt *Link, b *bio.Buf) { Flushplist(ctxt) WriteObjFile(ctxt, b) } @@ -373,16 +374,16 @@ func (w *objWriter) writeLengths() { w.writeInt(int64(w.nFile)) } -func newObjWriter(ctxt *Link, b *Biobuf) *objWriter { +func newObjWriter(ctxt *Link, b *bio.Buf) *objWriter { return &objWriter{ ctxt: ctxt, - wr: b.w, + wr: b.Writer(), vrefIdx: make(map[string]int), refIdx: make(map[string]int), } } -func WriteObjFile(ctxt *Link, b *Biobuf) { +func WriteObjFile(ctxt *Link, b *bio.Buf) { w := newObjWriter(ctxt, b) // Magic header diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go index 245fab9690..04e6a76e1a 100644 --- a/src/cmd/internal/obj/util.go +++ b/src/cmd/internal/obj/util.go @@ -5,10 +5,8 @@ package obj import ( - "bufio" "bytes" "fmt" - "io" "log" "os" "strings" @@ -26,144 +24,6 @@ func Cputime() float64 { return time.Since(start).Seconds() } -type Biobuf struct { - f *os.File - r *bufio.Reader - w *bufio.Writer - linelen int -} - -func (b *Biobuf) Reader() *bufio.Reader { return b.r } - -func Bopenw(name string) (*Biobuf, error) { - f, err := os.Create(name) - if err != nil { - return nil, err - } - return &Biobuf{f: f, w: bufio.NewWriter(f)}, nil -} - -func Bopenr(name string) (*Biobuf, error) { - f, err := os.Open(name) - if err != nil { - return nil, err - } - return &Biobuf{f: f, r: bufio.NewReader(f)}, nil -} - -func Binitw(w io.Writer) *Biobuf { - return &Biobuf{w: bufio.NewWriter(w)} -} - -func Binitr(r io.Reader) *Biobuf { - return &Biobuf{r: bufio.NewReader(r)} -} - -func (b *Biobuf) Write(p []byte) (int, error) { - return b.w.Write(p) -} - -func Bwritestring(b *Biobuf, p string) (int, error) { - return b.w.WriteString(p) -} - -func Bseek(b *Biobuf, offset int64, whence int) int64 { - if b.w != nil { - if err := b.w.Flush(); err != nil { - log.Fatalf("writing output: %v", err) - } - } else if b.r != nil { - if whence == 1 { - offset -= int64(b.r.Buffered()) - } - } - off, err := b.f.Seek(offset, whence) - if err != nil { - log.Fatalf("seeking in output: %v", err) - } - if b.r != nil { - b.r.Reset(b.f) - } - return off -} - -func Boffset(b *Biobuf) int64 { - if b.w != nil { - if err := b.w.Flush(); err != nil { - log.Fatalf("writing output: %v", err) - } - } - off, err := b.f.Seek(0, 1) - if err != nil { - log.Fatalf("seeking in output [0, 1]: %v", err) - } - if b.r != nil { - off -= int64(b.r.Buffered()) - } - return off -} - -func (b *Biobuf) Flush() error { - return b.w.Flush() -} - -func Bputc(b *Biobuf, c byte) { - b.w.WriteByte(c) -} - -const Beof = -1 - -func Bread(b *Biobuf, p []byte) int { - n, err := io.ReadFull(b.r, p) - if n == 0 { - if err != nil && err != io.EOF { - n = -1 - } - } - return n -} - -func Bgetc(b *Biobuf) int { - c, err := b.r.ReadByte() - if err != nil { - return -1 - } - return int(c) -} - -func (b *Biobuf) Read(p []byte) (int, error) { - return b.r.Read(p) -} - -func (b *Biobuf) Peek(n int) ([]byte, error) { - return b.r.Peek(n) -} - -func Brdline(b *Biobuf, delim int) string { - s, err := b.r.ReadBytes(byte(delim)) - if err != nil { - log.Fatalf("reading input: %v", err) - } - b.linelen = len(s) - return string(s) -} - -func Blinelen(b *Biobuf) int { - return b.linelen -} - -func Bterm(b *Biobuf) error { - var err error - if b.w != nil { - err = b.w.Flush() - } - err1 := b.f.Close() - if err == nil { - err = err1 - } - return err -} - func envOr(key, value string) string { if x := os.Getenv(key); x != "" { return x diff --git a/src/cmd/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go index d07756071d..205773c7f8 100644 --- a/src/cmd/link/internal/ld/ar.go +++ b/src/cmd/link/internal/ld/ar.go @@ -31,6 +31,7 @@ package ld import ( + "cmd/internal/bio" "cmd/internal/obj" "encoding/binary" "fmt" @@ -62,7 +63,7 @@ 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. @@ -73,15 +74,15 @@ func hostArchive(name string) { } 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) { + if bio.Bread(f, magbuf) != len(magbuf) { Exitf("file %s too short", name) } var arhdr ArHdr - l := nextar(f, obj.Boffset(f), &arhdr) + l := nextar(f, bio.Boffset(f), &arhdr) if l <= 0 { Exitf("%s missing armap", name) } @@ -117,7 +118,7 @@ func hostArchive(name string) { l = atolwhex(arhdr.size) h := ldobj(f, "libgcc", l, pname, name, ArchiveObj) - obj.Bseek(f, h.off, 0) + bio.Bseek(f, h.off, 0) h.ld(f, h.pkg, h.length, h.pn) } @@ -130,7 +131,7 @@ 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.Buf, arhdr ArHdr) archiveMap { is64 := arhdr.name == "/SYM64/" wordSize := 4 if is64 { @@ -139,7 +140,7 @@ func readArmap(filename string, f *obj.Biobuf, arhdr ArHdr) archiveMap { l := atolwhex(arhdr.size) contents := make([]byte, l) - if obj.Bread(f, contents) != int(l) { + if bio.Bread(f, contents) != int(l) { Exitf("short read from %s", filename) } diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go index 027e05d845..8bafaffd7c 100644 --- a/src/cmd/link/internal/ld/go.go +++ b/src/cmd/link/internal/ld/go.go @@ -8,6 +8,7 @@ package ld import ( "bytes" + "cmd/internal/bio" "cmd/internal/obj" "fmt" "os" @@ -26,7 +27,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.Buf, pkg string, length int64, filename string, whence int) { var p0, p1 int if Debug['g'] != 0 { @@ -48,7 +49,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 int64(bio.Bread(f, bdata)) != length { fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename) if Debug['u'] != 0 { errorexit() diff --git a/src/cmd/link/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go index 485599be62..eafc6930d5 100644 --- a/src/cmd/link/internal/ld/ldelf.go +++ b/src/cmd/link/internal/ld/ldelf.go @@ -2,6 +2,7 @@ package ld import ( "bytes" + "cmd/internal/bio" "cmd/internal/obj" "cmd/internal/sys" "encoding/binary" @@ -267,7 +268,7 @@ type ElfSect struct { } type ElfObj struct { - f *obj.Biobuf + f *bio.Buf base int64 // offset in f where ELF begins length int64 // length of ELF is64 int @@ -446,13 +447,13 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) { } } -func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) { +func ldelf(f *bio.Buf, pkg string, length int64, pn string) { if Debug['v'] != 0 { fmt.Fprintf(&Bso, "%5.2f ldelf %s\n", obj.Cputime(), pn) } Ctxt.IncVersion() - base := int32(obj.Boffset(f)) + base := int32(bio.Boffset(f)) var add uint64 var e binary.ByteOrder @@ -475,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 bio.Bread(f, hdrbuf[:]) != len(hdrbuf) { goto bad } hdr = new(ElfHdrBytes) @@ -600,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 bio.Bseek(f, int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 { goto bad } sect = &elfobj.sect[i] @@ -986,7 +987,7 @@ 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) { + if bio.Bseek(elfobj.f, int64(uint64(elfobj.base)+sect.off), 0) < 0 || bio.Bread(elfobj.f, sect.base) != len(sect.base) { return err } diff --git a/src/cmd/link/internal/ld/ldmacho.go b/src/cmd/link/internal/ld/ldmacho.go index 9fbb2123af..6376116d04 100644 --- a/src/cmd/link/internal/ld/ldmacho.go +++ b/src/cmd/link/internal/ld/ldmacho.go @@ -1,6 +1,7 @@ package ld import ( + "cmd/internal/bio" "cmd/internal/obj" "cmd/internal/sys" "encoding/binary" @@ -42,7 +43,7 @@ const ( ) type LdMachoObj struct { - f *obj.Biobuf + f *bio.Buf base int64 // off in f where Mach-O begins length int64 // length of Mach-O is64 bool @@ -298,7 +299,7 @@ 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 bio.Bseek(m.f, m.base+int64(sect.reloff), 0) < 0 || bio.Bread(m.f, buf) != n { return -1 } var p []byte @@ -344,7 +345,7 @@ 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 bio.Bseek(m.f, m.base+int64(d.indirectsymoff), 0) < 0 || bio.Bread(m.f, p) != len(p) { return -1 } @@ -361,7 +362,7 @@ 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 bio.Bseek(m.f, m.base+int64(symtab.stroff), 0) < 0 || bio.Bread(m.f, strbuf) != len(strbuf) { return -1 } @@ -371,7 +372,7 @@ 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 bio.Bseek(m.f, m.base+int64(symtab.symoff), 0) < 0 || bio.Bread(m.f, symbuf) != len(symbuf) { return -1 } sym := make([]LdMachoSym, symtab.nsym) @@ -401,7 +402,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.Buf, pkg string, length int64, pn string) { var err error var j int var is64 bool @@ -431,8 +432,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 := bio.Boffset(f) + if bio.Bread(f, hdr[:]) != len(hdr) { goto bad } @@ -455,7 +456,7 @@ func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) { if is64 { var tmp [4]uint8 - obj.Bread(f, tmp[:4]) // skip reserved word in header + bio.Bread(f, tmp[:4]) // skip reserved word in header } m = new(LdMachoObj) @@ -493,7 +494,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 bio.Bread(f, cmdp) != len(cmdp) { err = fmt.Errorf("reading cmds: %v", err) goto bad } @@ -556,7 +557,7 @@ 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 bio.Bseek(f, m.base+int64(c.seg.fileoff), 0) < 0 || bio.Bread(f, dat) != len(dat) { err = fmt.Errorf("cannot load object data: %v", err) goto bad } diff --git a/src/cmd/link/internal/ld/ldpe.go b/src/cmd/link/internal/ld/ldpe.go index ea0c482838..e97e842e7f 100644 --- a/src/cmd/link/internal/ld/ldpe.go +++ b/src/cmd/link/internal/ld/ldpe.go @@ -5,6 +5,7 @@ package ld import ( + "cmd/internal/bio" "cmd/internal/obj" "cmd/internal/sys" "encoding/binary" @@ -117,7 +118,7 @@ type PeSect struct { } type PeObj struct { - f *obj.Biobuf + f *bio.Buf name string base uint32 sect []PeSect @@ -128,14 +129,14 @@ type PeObj struct { snames []byte } -func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) { +func ldpe(f *bio.Buf, pkg string, length int64, pn string) { if Debug['v'] != 0 { fmt.Fprintf(&Bso, "%5.2f ldpe %s\n", obj.Cputime(), pn) } var sect *PeSect Ctxt.IncVersion() - base := int32(obj.Boffset(f)) + base := int32(bio.Boffset(f)) peobj := new(PeObj) peobj.f = f @@ -173,15 +174,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) + bio.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0) - if obj.Bread(f, symbuf[:4]) != 4 { + if bio.Bread(f, symbuf[:4]) != 4 { 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) { + bio.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0) + if bio.Bread(f, peobj.snames) != len(peobj.snames) { goto bad } @@ -201,10 +202,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) + bio.Bseek(f, int64(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) { + bio.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0) + if bio.Bread(f, symbuf[:]) != len(symbuf) { goto bad } @@ -289,10 +290,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) + bio.Bseek(f, 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 bio.Bread(f, symbuf[:10]) != 10 { goto bad } rva := Le32(symbuf[0:]) @@ -465,7 +466,7 @@ 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 bio.Bseek(peobj.f, int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 || bio.Bread(peobj.f, sect.base) != len(sect.base) { return -1 } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 305a3bc0db..789eaef1a5 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -33,6 +33,7 @@ package ld import ( "bufio" "bytes" + "cmd/internal/bio" "cmd/internal/obj" "cmd/internal/sys" "crypto/sha1" @@ -240,7 +241,7 @@ const ( var ( headstring string // buffered output - Bso obj.Biobuf + Bso bio.Buf ) type outBuf struct { @@ -738,13 +739,13 @@ 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.Buf, off int64, a *ArHdr) int64 { if off&1 != 0 { off++ } - obj.Bseek(bp, off, 0) + bio.Bseek(bp, off, 0) buf := make([]byte, SAR_HDR) - if n := obj.Bread(bp, buf); n < len(buf) { + if n := bio.Bread(bp, buf); n < len(buf) { if n >= 0 { return 0 } @@ -773,25 +774,25 @@ func objfile(lib *Library) { 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) { + if bio.Bread(f, magbuf) != len(magbuf) || !strings.HasPrefix(string(magbuf), ARMAG) { /* load it as a regular file */ - l := obj.Bseek(f, 0, 2) + l := bio.Bseek(f, 0, 2) - obj.Bseek(f, 0, 0) + bio.Bseek(f, 0, 0) ldobj(f, pkg, l, lib.File, lib.File, FileObj) - obj.Bterm(f) + f.Close() return } /* process __.PKGDEF */ - off := obj.Boffset(f) + off := bio.Boffset(f) var arhdr ArHdr l := nextar(f, off, &arhdr) @@ -807,12 +808,12 @@ func objfile(lib *Library) { } if Buildmode == BuildmodeShared { - before := obj.Boffset(f) + before := bio.Boffset(f) pkgdefBytes := make([]byte, atolwhex(arhdr.size)) - obj.Bread(f, pkgdefBytes) + bio.Bread(f, pkgdefBytes) hash := sha1.Sum(pkgdefBytes) lib.hash = hash[:] - obj.Bseek(f, before, 0) + bio.Bseek(f, before, 0) } off += l @@ -848,11 +849,11 @@ func objfile(lib *Library) { } out: - obj.Bterm(f) + f.Close() } type Hostobj struct { - ld func(*obj.Biobuf, string, int64, string) + ld func(*bio.Buf, string, int64, string) pkg string pn string file string @@ -873,7 +874,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.Buf, string, int64, string), f *bio.Buf, pkg string, length int64, pn string, file string) *Hostobj { isinternal := false for i := 0; i < len(internalpkg); i++ { if pkg == internalpkg[i] { @@ -904,26 +905,26 @@ 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 = bio.Boffset(f) h.length = length return h } func hostobjs() { - var f *obj.Biobuf + var f *bio.Buf var h *Hostobj for i := 0; i < len(hostobj); i++ { h = &hostobj[i] var err error - f, err = obj.Bopenr(h.file) + f, err = bio.Open(h.file) if f == nil { Exitf("cannot reopen %s: %v", h.pn, err) } - obj.Bseek(f, h.off, 0) + bio.Bseek(f, h.off, 0) h.ld(f, h.pkg, h.length, h.pn) - obj.Bterm(f) + f.Close() } } @@ -1265,15 +1266,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.Buf, pkg string, length int64, pn string, file string, whence int) *Hostobj { + eof := bio.Boffset(f) + 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 := bio.Boffset(f) + c1 := bio.Bgetc(f) + c2 := bio.Bgetc(f) + c3 := bio.Bgetc(f) + c4 := bio.Bgetc(f) + bio.Bseek(f, start, 0) magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4) if magic == 0x7f454c46 { // \x7F E L F @@ -1289,12 +1290,8 @@ func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, when } /* check the header */ - line := obj.Brdline(f, '\n') + line := bio.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) return nil } @@ -1337,28 +1334,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 := bio.Boffset(f) c1 = '\n' // the last line ended in \n - c2 = obj.Bgetc(f) - c3 = obj.Bgetc(f) + c2 = bio.Bgetc(f) + c3 = bio.Bgetc(f) for c1 != '\n' || c2 != '!' || c3 != '\n' { c1 = c2 c2 = c3 - c3 = obj.Bgetc(f) - if c3 == obj.Beof { + c3 = bio.Bgetc(f) + if c3 == bio.EOF { Diag("truncated object file: %s", pn) return nil } } - import1 := obj.Boffset(f) + import1 := bio.Boffset(f) - obj.Bseek(f, import0, 0) + bio.Bseek(f, import0, 0) ldpkg(f, pkg, import1-import0-2, pn, whence) // -2 for !\n - obj.Bseek(f, import1, 0) + bio.Bseek(f, import1, 0) - LoadObjFile(Ctxt, f, pkg, eof-obj.Boffset(f), pn) + LoadObjFile(Ctxt, f, pkg, eof-bio.Boffset(f), pn) return nil } diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index f0811389d2..d3f9ed3703 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -31,7 +31,7 @@ package ld import ( - "cmd/internal/obj" + "cmd/internal/bio" "cmd/internal/sys" "debug/elf" "fmt" @@ -165,7 +165,7 @@ type Link struct { Headtype int Arch *sys.Arch Debugvlog int32 - Bso *obj.Biobuf + Bso *bio.Buf Windows int32 Goroot string diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go index 8a406d17a6..6f177861f0 100644 --- a/src/cmd/link/internal/ld/objfile.go +++ b/src/cmd/link/internal/ld/objfile.go @@ -110,6 +110,7 @@ package ld import ( "bufio" "bytes" + "cmd/internal/bio" "cmd/internal/obj" "io" "log" @@ -146,8 +147,8 @@ 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.Buf, pkg string, length int64, pn string) { + start := bio.Boffset(f) r := &objReader{ rd: f.Reader(), pkg: pkg, @@ -156,8 +157,8 @@ func LoadObjFile(ctxt *Link, f *obj.Biobuf, pkg string, length int64, pn string) 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 bio.Boffset(f) != start+length { + log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(bio.Boffset(f)), int64(start+length)) } } diff --git a/src/cmd/link/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go index b9902a5e5e..bb48f13185 100644 --- a/src/cmd/link/internal/ld/pobj.go +++ b/src/cmd/link/internal/ld/pobj.go @@ -31,6 +31,7 @@ package ld import ( + "cmd/internal/bio" "cmd/internal/obj" "cmd/internal/sys" "flag" @@ -49,7 +50,7 @@ func Ldmain() { Ctxt.Diag = Diag Ctxt.Bso = &Bso - Bso = *obj.Binitw(os.Stdout) + Bso = *bio.BufWriter(os.Stdout) Debug = [128]int{} nerrors = 0 outfile = "" -- cgit v1.3-5-g9baa From 438ce713a1c8e4d24aea547b6fcf907b5dbf0bec Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 6 Apr 2016 23:34:32 -0700 Subject: cmd/link/internal/amd64: remove empty source file Change-Id: I2da012ed996c669db513a462f014c6f3ffa396ee Reviewed-on: https://go-review.googlesource.com/21646 Reviewed-by: Mikio Hara --- src/cmd/link/internal/amd64/z.go | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/cmd/link/internal/amd64/z.go (limited to 'src/cmd/link') 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 -- cgit v1.3-5-g9baa From e6181eb9e1dc4ab9e297a102ed192997582ac46c Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Thu, 7 Apr 2016 14:00:00 -0400 Subject: cmd/link: disable DWARF when not generating symtab Fixes #15166 Change-Id: I30284e3c0fb2c80b26a2572e2fb249b8018e85f9 Reviewed-on: https://go-review.googlesource.com/21587 Run-TryBot: David Crawshaw Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/dwarf.go | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 230d146877..db8961676c 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -1915,6 +1915,9 @@ func dwarfgeneratedebugsyms() { if Debug['w'] != 0 { // disable dwarf return } + if Debug['s'] != 0 && HEADTYPE != obj.Hdarwin { + return + } if HEADTYPE == obj.Hplan9 { return } -- cgit v1.3-5-g9baa From 9658b7ef83ae9c34f4a52680e7102d958577d5bb Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Thu, 7 Apr 2016 14:27:15 -0400 Subject: cmd/link: hide go.dwarf symbols Fixes #15179 Change-Id: I0f70b7ae1682eafaece7f22d8e76f0aa806f3ec9 Reviewed-on: https://go-review.googlesource.com/21589 Run-TryBot: David Crawshaw Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/dwarf.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index db8961676c..4741020a6d 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -509,6 +509,7 @@ func newdie(parent *DWDie, abbrev int, name string, version int) *DWDie { 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 } } @@ -814,6 +815,7 @@ func dotypedef(parent *DWDie, name string, def *DWDie) { } 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, -- cgit v1.3-5-g9baa From 8f2edf11998a30b497586ac0e9f75036a318280a Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Fri, 8 Apr 2016 19:14:03 +1000 Subject: cmd: replace bio.Buf with bio.Reader and bio.Writer Replace the bidirectional bio.Buf type with a pair of unidirectional buffered seekable Reader and Writers. Change-Id: I86664a06f93c94595dc67c2cbd21356feb6680ef Reviewed-on: https://go-review.googlesource.com/21720 Reviewed-by: Brad Fitzpatrick Run-TryBot: Dave Cheney TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/bexport.go | 4 +- src/cmd/compile/internal/gc/go.go | 4 +- src/cmd/compile/internal/gc/obj.go | 16 ++-- src/cmd/internal/bio/buf.go | 137 +++++++++++++++++++-------------- src/cmd/internal/obj/link.go | 2 +- src/cmd/internal/obj/objfile.go | 6 +- src/cmd/link/internal/ld/ar.go | 6 +- src/cmd/link/internal/ld/go.go | 2 +- src/cmd/link/internal/ld/ldelf.go | 10 +-- src/cmd/link/internal/ld/ldmacho.go | 16 ++-- src/cmd/link/internal/ld/ldpe.go | 18 ++--- src/cmd/link/internal/ld/lib.go | 49 ++++++------ src/cmd/link/internal/ld/link.go | 7 +- src/cmd/link/internal/ld/objfile.go | 8 +- 14 files changed, 154 insertions(+), 131 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index 909ff14982..bb0a34e67b 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -124,7 +124,7 @@ const exportVersion = "v0" const exportInlined = true // default: true type exporter struct { - out *bio.Buf + out *bio.Writer pkgIndex map[*Pkg]int typIndex map[*Type]int inlined []*Func @@ -136,7 +136,7 @@ type exporter struct { } // export writes the exportlist for localpkg to out and returns the number of bytes written. -func export(out *bio.Buf, trace bool) int { +func export(out *bio.Writer, trace bool) int { p := exporter{ out: out, pkgIndex: make(map[*Pkg]int), diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index cd9db38fb4..ec7e219d95 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -133,7 +133,7 @@ var infile string var outfile string -var bout *bio.Buf +var bout *bio.Writer var nerrors int @@ -288,7 +288,7 @@ var Ctxt *obj.Link var writearchive int -var bstdout *bio.Buf +var bstdout *bio.Writer var Nacl bool diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index 3920e25224..23c8be645c 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -37,7 +37,7 @@ func dumpobj() { bout.WriteString("!\n") arhdr = [ArhdrSize]byte{} bout.Write(arhdr[:]) - startobj = bio.Boffset(bout) + startobj = bout.Offset() } fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring()) @@ -45,19 +45,19 @@ func dumpobj() { if writearchive != 0 { bout.Flush() - size := bio.Boffset(bout) - startobj + size := bout.Offset() - startobj if size&1 != 0 { bout.WriteByte(0) } - bio.Bseek(bout, startobj-ArhdrSize, 0) + bout.Seek(startobj-ArhdrSize, 0) formathdr(arhdr[:], "__.PKGDEF", size) bout.Write(arhdr[:]) bout.Flush() - bio.Bseek(bout, startobj+size+(size&1), 0) + bout.Seek(startobj+size+(size&1), 0) arhdr = [ArhdrSize]byte{} bout.Write(arhdr[:]) - startobj = bio.Boffset(bout) + startobj = bout.Offset() fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring()) } @@ -92,11 +92,11 @@ func dumpobj() { if writearchive != 0 { bout.Flush() - size := bio.Boffset(bout) - startobj + size := bout.Offset() - startobj if size&1 != 0 { bout.WriteByte(0) } - bio.Bseek(bout, startobj-ArhdrSize, 0) + bout.Seek(startobj-ArhdrSize, 0) formathdr(arhdr[:], "_go_.o", size) bout.Write(arhdr[:]) } @@ -133,7 +133,7 @@ func dumpglobls() { funcsyms = nil } -func Bputname(b *bio.Buf, s *obj.LSym) { +func Bputname(b *bio.Writer, s *obj.LSym) { b.WriteString(s.Name) b.WriteByte(0) } diff --git a/src/cmd/internal/bio/buf.go b/src/cmd/internal/bio/buf.go index a1df26ca9c..0bd4658cdd 100644 --- a/src/cmd/internal/bio/buf.go +++ b/src/cmd/internal/bio/buf.go @@ -14,94 +14,116 @@ import ( const EOF = -1 -// Buf implements a seekable buffered I/O abstraction. -type Buf struct { +// Reader implements a seekable buffered io.Reader. +type Reader struct { f *os.File r *bufio.Reader +} + +// Writer implements a seekable buffered io.Writer. +type Writer struct { + f *os.File w *bufio.Writer } -func (b *Buf) Reader() *bufio.Reader { return b.r } -func (b *Buf) Writer() *bufio.Writer { return b.w } +// Reader returns this Reader's underlying bufio.Reader. +func (r *Reader) Reader() *bufio.Reader { return r.r } -func Create(name string) (*Buf, error) { +// Writer returns this Writer's underlying bufio.Writer. +func (w *Writer) Writer() *bufio.Writer { return w.w } + +// Create creates the file named name and returns a Writer +// for that file. +func Create(name string) (*Writer, error) { f, err := os.Create(name) if err != nil { return nil, err } - return &Buf{f: f, w: bufio.NewWriter(f)}, nil + return &Writer{f: f, w: bufio.NewWriter(f)}, nil } -func Open(name string) (*Buf, error) { +// Open returns a Reader for the file named name. +func Open(name string) (*Reader, error) { f, err := os.Open(name) if err != nil { return nil, err } - return &Buf{f: f, r: bufio.NewReader(f)}, nil + return &Reader{f: f, r: bufio.NewReader(f)}, nil } -func BufWriter(w io.Writer) *Buf { - return &Buf{w: bufio.NewWriter(w)} +// BufWriter returns a Writer on top of w. +// TODO(dfc) remove this method and replace caller with bufio.Writer. +func BufWriter(w io.Writer) *Writer { + return &Writer{w: bufio.NewWriter(w)} } -func BufReader(r io.Reader) *Buf { - return &Buf{r: bufio.NewReader(r)} +// BufWriter returns a Reader on top of r. +// TODO(dfc) remove this method and replace caller with bufio.Reader. +func BufReader(r io.Reader) *Reader { + return &Reader{r: bufio.NewReader(r)} } -func (b *Buf) Write(p []byte) (int, error) { - return b.w.Write(p) +func (w *Writer) Write(p []byte) (int, error) { + return w.w.Write(p) } -func (b *Buf) WriteString(p string) (int, error) { - return b.w.WriteString(p) +func (w *Writer) WriteString(p string) (int, error) { + return w.w.WriteString(p) } -func Bseek(b *Buf, offset int64, whence int) int64 { - if b.w != nil { - if err := b.w.Flush(); err != nil { - log.Fatalf("writing output: %v", err) - } - } else if b.r != nil { - if whence == 1 { - offset -= int64(b.r.Buffered()) - } +func (r *Reader) Seek(offset int64, whence int) int64 { + if whence == 1 { + offset -= int64(r.r.Buffered()) } - off, err := b.f.Seek(offset, whence) + off, err := r.f.Seek(offset, whence) if err != nil { log.Fatalf("seeking in output: %v", err) } - if b.r != nil { - b.r.Reset(b.f) - } + r.r.Reset(r.f) return off } -func Boffset(b *Buf) int64 { - if b.w != nil { - if err := b.w.Flush(); err != nil { - log.Fatalf("writing output: %v", err) - } +func (w *Writer) Seek(offset int64, whence int) int64 { + if err := w.w.Flush(); err != nil { + log.Fatalf("writing output: %v", err) } - off, err := b.f.Seek(0, 1) + off, err := w.f.Seek(offset, whence) + if err != nil { + log.Fatalf("seeking in output: %v", err) + } + return off +} + +func (r *Reader) Offset() int64 { + off, err := r.f.Seek(0, 1) if err != nil { log.Fatalf("seeking in output [0, 1]: %v", err) } - if b.r != nil { - off -= int64(b.r.Buffered()) + off -= int64(r.r.Buffered()) + return off +} + +func (w *Writer) Offset() int64 { + if err := w.w.Flush(); err != nil { + log.Fatalf("writing output: %v", err) + } + off, err := w.f.Seek(0, 1) + if err != nil { + log.Fatalf("seeking in output [0, 1]: %v", err) } return off } -func (b *Buf) Flush() error { - return b.w.Flush() +func (w *Writer) Flush() error { + return w.w.Flush() } -func (b *Buf) WriteByte(c byte) error { - return b.w.WriteByte(c) +func (w *Writer) WriteByte(c byte) error { + return w.w.WriteByte(c) } -func Bread(b *Buf, p []byte) int { - n, err := io.ReadFull(b.r, p) +func Bread(r *Reader, p []byte) int { + n, err := io.ReadFull(r.r, p) if n == 0 { if err != nil && err != io.EOF { n = -1 @@ -110,8 +132,8 @@ func Bread(b *Buf, p []byte) int { return n } -func Bgetc(b *Buf) int { - c, err := b.r.ReadByte() +func Bgetc(r *Reader) int { + c, err := r.r.ReadByte() if err != nil { if err != io.EOF { log.Fatalf("reading input: %v", err) @@ -121,28 +143,29 @@ func Bgetc(b *Buf) int { return int(c) } -func (b *Buf) Read(p []byte) (int, error) { - return b.r.Read(p) +func (r *Reader) Read(p []byte) (int, error) { + return r.r.Read(p) } -func (b *Buf) Peek(n int) ([]byte, error) { - return b.r.Peek(n) +func (r *Reader) Peek(n int) ([]byte, error) { + return r.r.Peek(n) } -func Brdline(b *Buf, delim int) string { - s, err := b.r.ReadBytes(byte(delim)) +func Brdline(r *Reader, delim int) string { + s, err := r.r.ReadBytes(byte(delim)) if err != nil { log.Fatalf("reading input: %v", err) } return string(s) } -func (b *Buf) Close() error { - var err error - if b.w != nil { - err = b.w.Flush() - } - err1 := b.f.Close() +func (r *Reader) Close() error { + return r.f.Close() +} + +func (w *Writer) Close() error { + err := w.w.Flush() + err1 := w.f.Close() if err == nil { err = err1 } diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 2c81ca2f08..c48c3d807f 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -629,7 +629,7 @@ type Link struct { Flag_shared int32 Flag_dynlink bool Flag_optimize bool - Bso *bio.Buf + Bso *bio.Writer Pathname string Goroot string Goroot_final string diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index 405cbf446a..ed6d75eba3 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -121,7 +121,7 @@ import ( // The Go and C compilers, and the assembler, call writeobj to write // out a Go object file. The linker does not call this; the linker // does not write out object files. -func Writeobjdirect(ctxt *Link, b *bio.Buf) { +func Writeobjdirect(ctxt *Link, b *bio.Writer) { Flushplist(ctxt) WriteObjFile(ctxt, b) } @@ -374,7 +374,7 @@ func (w *objWriter) writeLengths() { w.writeInt(int64(w.nFile)) } -func newObjWriter(ctxt *Link, b *bio.Buf) *objWriter { +func newObjWriter(ctxt *Link, b *bio.Writer) *objWriter { return &objWriter{ ctxt: ctxt, wr: b.Writer(), @@ -383,7 +383,7 @@ func newObjWriter(ctxt *Link, b *bio.Buf) *objWriter { } } -func WriteObjFile(ctxt *Link, b *bio.Buf) { +func WriteObjFile(ctxt *Link, b *bio.Writer) { w := newObjWriter(ctxt, b) // Magic header diff --git a/src/cmd/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go index 205773c7f8..6a0aeb121f 100644 --- a/src/cmd/link/internal/ld/ar.go +++ b/src/cmd/link/internal/ld/ar.go @@ -82,7 +82,7 @@ func hostArchive(name string) { } var arhdr ArHdr - l := nextar(f, bio.Boffset(f), &arhdr) + l := nextar(f, f.Offset(), &arhdr) if l <= 0 { Exitf("%s missing armap", name) } @@ -118,7 +118,7 @@ func hostArchive(name string) { l = atolwhex(arhdr.size) h := ldobj(f, "libgcc", l, pname, name, ArchiveObj) - bio.Bseek(f, h.off, 0) + f.Seek(h.off, 0) h.ld(f, h.pkg, h.length, h.pn) } @@ -131,7 +131,7 @@ func hostArchive(name string) { type archiveMap map[string]uint64 // readArmap reads the archive symbol map. -func readArmap(filename string, f *bio.Buf, arhdr ArHdr) archiveMap { +func readArmap(filename string, f *bio.Reader, arhdr ArHdr) archiveMap { is64 := arhdr.name == "/SYM64/" wordSize := 4 if is64 { diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go index 8bafaffd7c..5dad90dae6 100644 --- a/src/cmd/link/internal/ld/go.go +++ b/src/cmd/link/internal/ld/go.go @@ -27,7 +27,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 *bio.Buf, 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 { diff --git a/src/cmd/link/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go index eafc6930d5..55884c07a2 100644 --- a/src/cmd/link/internal/ld/ldelf.go +++ b/src/cmd/link/internal/ld/ldelf.go @@ -268,7 +268,7 @@ type ElfSect struct { } type ElfObj struct { - f *bio.Buf + f *bio.Reader base int64 // offset in f where ELF begins length int64 // length of ELF is64 int @@ -447,13 +447,13 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) { } } -func ldelf(f *bio.Buf, 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) } Ctxt.IncVersion() - base := int32(bio.Boffset(f)) + base := f.Offset() var add uint64 var e binary.ByteOrder @@ -601,7 +601,7 @@ func ldelf(f *bio.Buf, pkg string, length int64, pn string) { elfobj.nsect = uint(elfobj.shnum) for i := 0; uint(i) < elfobj.nsect; i++ { - if bio.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] @@ -987,7 +987,7 @@ func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) { sect.base = make([]byte, sect.size) err = fmt.Errorf("short read") - if bio.Bseek(elfobj.f, int64(uint64(elfobj.base)+sect.off), 0) < 0 || bio.Bread(elfobj.f, sect.base) != len(sect.base) { + if elfobj.f.Seek(int64(uint64(elfobj.base)+sect.off), 0) < 0 || bio.Bread(elfobj.f, sect.base) != len(sect.base) { return err } diff --git a/src/cmd/link/internal/ld/ldmacho.go b/src/cmd/link/internal/ld/ldmacho.go index 6376116d04..dffe6f69ce 100644 --- a/src/cmd/link/internal/ld/ldmacho.go +++ b/src/cmd/link/internal/ld/ldmacho.go @@ -43,7 +43,7 @@ const ( ) type LdMachoObj struct { - f *bio.Buf + f *bio.Reader base int64 // off in f where Mach-O begins length int64 // length of Mach-O is64 bool @@ -299,7 +299,7 @@ func macholoadrel(m *LdMachoObj, sect *LdMachoSect) int { rel := make([]LdMachoRel, sect.nreloc) n := int(sect.nreloc * 8) buf := make([]byte, n) - if bio.Bseek(m.f, m.base+int64(sect.reloff), 0) < 0 || bio.Bread(m.f, buf) != n { + if m.f.Seek(m.base+int64(sect.reloff), 0) < 0 || bio.Bread(m.f, buf) != n { return -1 } var p []byte @@ -345,7 +345,7 @@ func macholoaddsym(m *LdMachoObj, d *LdMachoDysymtab) int { n := int(d.nindirectsyms) p := make([]byte, n*4) - if bio.Bseek(m.f, m.base+int64(d.indirectsymoff), 0) < 0 || bio.Bread(m.f, p) != len(p) { + if m.f.Seek(m.base+int64(d.indirectsymoff), 0) < 0 || bio.Bread(m.f, p) != len(p) { return -1 } @@ -362,7 +362,7 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int { } strbuf := make([]byte, symtab.strsize) - if bio.Bseek(m.f, m.base+int64(symtab.stroff), 0) < 0 || bio.Bread(m.f, strbuf) != len(strbuf) { + if m.f.Seek(m.base+int64(symtab.stroff), 0) < 0 || bio.Bread(m.f, strbuf) != len(strbuf) { return -1 } @@ -372,7 +372,7 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int { } n := int(symtab.nsym * uint32(symsize)) symbuf := make([]byte, n) - if bio.Bseek(m.f, m.base+int64(symtab.symoff), 0) < 0 || bio.Bread(m.f, symbuf) != len(symbuf) { + if m.f.Seek(m.base+int64(symtab.symoff), 0) < 0 || bio.Bread(m.f, symbuf) != len(symbuf) { return -1 } sym := make([]LdMachoSym, symtab.nsym) @@ -402,7 +402,7 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int { return 0 } -func ldmacho(f *bio.Buf, 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 @@ -432,7 +432,7 @@ func ldmacho(f *bio.Buf, pkg string, length int64, pn string) { var name string Ctxt.IncVersion() - base := bio.Boffset(f) + base := f.Offset() if bio.Bread(f, hdr[:]) != len(hdr) { goto bad } @@ -557,7 +557,7 @@ func ldmacho(f *bio.Buf, pkg string, length int64, pn string) { } dat = make([]byte, c.seg.filesz) - if bio.Bseek(f, m.base+int64(c.seg.fileoff), 0) < 0 || bio.Bread(f, dat) != len(dat) { + if f.Seek(m.base+int64(c.seg.fileoff), 0) < 0 || bio.Bread(f, dat) != len(dat) { err = fmt.Errorf("cannot load object data: %v", err) goto bad } diff --git a/src/cmd/link/internal/ld/ldpe.go b/src/cmd/link/internal/ld/ldpe.go index e97e842e7f..ba5b928ea0 100644 --- a/src/cmd/link/internal/ld/ldpe.go +++ b/src/cmd/link/internal/ld/ldpe.go @@ -118,7 +118,7 @@ type PeSect struct { } type PeObj struct { - f *bio.Buf + f *bio.Reader name string base uint32 sect []PeSect @@ -129,14 +129,14 @@ type PeObj struct { snames []byte } -func ldpe(f *bio.Buf, 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) } var sect *PeSect Ctxt.IncVersion() - base := int32(bio.Boffset(f)) + base := f.Offset() peobj := new(PeObj) peobj.f = f @@ -174,14 +174,14 @@ func ldpe(f *bio.Buf, pkg string, length int64, pn string) { // TODO return error if found .cormeta // load string table - bio.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0) + f.Seek(int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0) if bio.Bread(f, symbuf[:4]) != 4 { goto bad } l = Le32(symbuf[:]) peobj.snames = make([]byte, l) - bio.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0) + f.Seek(int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0) if bio.Bread(f, peobj.snames) != len(peobj.snames) { goto bad } @@ -202,9 +202,9 @@ func ldpe(f *bio.Buf, pkg string, length int64, pn string) { peobj.pesym = make([]PeSym, peobj.fh.NumberOfSymbols) peobj.npesym = uint(peobj.fh.NumberOfSymbols) - bio.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable), 0) + f.Seek(int64(base)+int64(peobj.fh.PointerToSymbolTable), 0) for i := 0; uint32(i) < peobj.fh.NumberOfSymbols; i += numaux + 1 { - bio.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0) + f.Seek(int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0) if bio.Bread(f, symbuf[:]) != len(symbuf) { goto bad } @@ -290,7 +290,7 @@ func ldpe(f *bio.Buf, pkg string, length int64, pn string) { } r = make([]Reloc, rsect.sh.NumberOfRelocations) - bio.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 bio.Bread(f, symbuf[:10]) != 10 { @@ -466,7 +466,7 @@ func pemap(peobj *PeObj, sect *PeSect) int { if sect.sh.PointerToRawData == 0 { // .bss doesn't have data in object file return 0 } - if bio.Bseek(peobj.f, int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 || bio.Bread(peobj.f, sect.base) != len(sect.base) { + if peobj.f.Seek(int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 || bio.Bread(peobj.f, sect.base) != len(sect.base) { return -1 } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 789eaef1a5..f8cc995c30 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -241,9 +241,10 @@ const ( var ( headstring string // buffered output - Bso bio.Buf + Bso bio.Writer ) +// TODO(dfc) outBuf duplicates bio.Writer type outBuf struct { w *bufio.Writer f *os.File @@ -739,11 +740,11 @@ func loadlib() { * look for the next file in an archive. * adapted from libmach. */ -func nextar(bp *bio.Buf, off int64, a *ArHdr) int64 { +func nextar(bp *bio.Reader, off int64, a *ArHdr) int64 { if off&1 != 0 { off++ } - bio.Bseek(bp, off, 0) + bp.Seek(off, 0) buf := make([]byte, SAR_HDR) if n := bio.Bread(bp, buf); n < len(buf) { if n >= 0 { @@ -782,9 +783,9 @@ func objfile(lib *Library) { magbuf := make([]byte, len(ARMAG)) if bio.Bread(f, magbuf) != len(magbuf) || !strings.HasPrefix(string(magbuf), ARMAG) { /* load it as a regular file */ - l := bio.Bseek(f, 0, 2) + l := f.Seek(0, 2) - bio.Bseek(f, 0, 0) + f.Seek(0, 0) ldobj(f, pkg, l, lib.File, lib.File, FileObj) f.Close() @@ -792,7 +793,7 @@ func objfile(lib *Library) { } /* process __.PKGDEF */ - off := bio.Boffset(f) + off := f.Offset() var arhdr ArHdr l := nextar(f, off, &arhdr) @@ -808,12 +809,12 @@ func objfile(lib *Library) { } if Buildmode == BuildmodeShared { - before := bio.Boffset(f) + before := f.Offset() pkgdefBytes := make([]byte, atolwhex(arhdr.size)) bio.Bread(f, pkgdefBytes) hash := sha1.Sum(pkgdefBytes) lib.hash = hash[:] - bio.Bseek(f, before, 0) + f.Seek(before, 0) } off += l @@ -853,7 +854,7 @@ out: } type Hostobj struct { - ld func(*bio.Buf, string, int64, string) + ld func(*bio.Reader, string, int64, string) pkg string pn string file string @@ -874,7 +875,7 @@ var internalpkg = []string{ "runtime/msan", } -func ldhostobj(ld func(*bio.Buf, string, int64, string), f *bio.Buf, 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] { @@ -905,24 +906,22 @@ func ldhostobj(ld func(*bio.Buf, string, int64, string), f *bio.Buf, pkg string, h.pkg = pkg h.pn = pn h.file = file - h.off = bio.Boffset(f) + h.off = f.Offset() h.length = length return h } func hostobjs() { - var f *bio.Buf var h *Hostobj for i := 0; i < len(hostobj); i++ { h = &hostobj[i] - var err error - f, err = bio.Open(h.file) - if f == nil { + f, err := bio.Open(h.file) + if err != nil { Exitf("cannot reopen %s: %v", h.pn, err) } - bio.Bseek(f, h.off, 0) + f.Seek(h.off, 0) h.ld(f, h.pkg, h.length, h.pn) f.Close() } @@ -1266,15 +1265,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 *bio.Buf, pkg string, length int64, pn string, file string, whence int) *Hostobj { - eof := bio.Boffset(f) + length +func ldobj(f *bio.Reader, pkg string, length int64, pn string, file string, whence int) *Hostobj { + eof := f.Offset() + length - start := bio.Boffset(f) + start := f.Offset() c1 := bio.Bgetc(f) c2 := bio.Bgetc(f) c3 := bio.Bgetc(f) c4 := bio.Bgetc(f) - bio.Bseek(f, start, 0) + f.Seek(start, 0) magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4) if magic == 0x7f454c46 { // \x7F E L F @@ -1334,7 +1333,7 @@ func ldobj(f *bio.Buf, pkg string, length int64, pn string, file string, whence } /* skip over exports and other info -- ends with \n!\n */ - import0 := bio.Boffset(f) + import0 := f.Offset() c1 = '\n' // the last line ended in \n c2 = bio.Bgetc(f) @@ -1349,13 +1348,13 @@ func ldobj(f *bio.Buf, pkg string, length int64, pn string, file string, whence } } - import1 := bio.Boffset(f) + import1 := f.Offset() - bio.Bseek(f, import0, 0) + f.Seek(import0, 0) ldpkg(f, pkg, import1-import0-2, pn, whence) // -2 for !\n - bio.Bseek(f, import1, 0) + f.Seek(import1, 0) - LoadObjFile(Ctxt, f, pkg, eof-bio.Boffset(f), pn) + LoadObjFile(Ctxt, f, pkg, eof-f.Offset(), pn) return nil } diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index d3f9ed3703..cbcc979c85 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -165,9 +165,10 @@ type Link struct { Headtype int Arch *sys.Arch Debugvlog int32 - Bso *bio.Buf - Windows int32 - Goroot string + + Bso *bio.Writer + Windows int32 + Goroot string // Symbol lookup based on name and indexed by version. Hash []map[string]*LSym diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go index 6f177861f0..61a67cf94c 100644 --- a/src/cmd/link/internal/ld/objfile.go +++ b/src/cmd/link/internal/ld/objfile.go @@ -147,8 +147,8 @@ type objReader struct { file []*LSym } -func LoadObjFile(ctxt *Link, f *bio.Buf, pkg string, length int64, pn string) { - start := bio.Boffset(f) +func LoadObjFile(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) { + start := f.Offset() r := &objReader{ rd: f.Reader(), pkg: pkg, @@ -157,8 +157,8 @@ func LoadObjFile(ctxt *Link, f *bio.Buf, pkg string, length int64, pn string) { dupSym: &LSym{Name: ".dup"}, } r.loadObjFile() - if bio.Boffset(f) != start+length { - log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(bio.Boffset(f)), int64(start+length)) + if f.Offset() != start+length { + log.Fatalf("%s: unexpected end at %d, want %d", pn, f.Offset(), start+length) } } -- cgit v1.3-5-g9baa From 78715cebcfcca3aaaaba4dd41ef6b82a46d7b93d Mon Sep 17 00:00:00 2001 From: Michael Munday Date: Fri, 8 Apr 2016 11:55:05 -0400 Subject: cmd/link: add s390x to link tool main function Change-Id: I83bc2b4a00216b069f133113e4ae9ad76c98a708 Reviewed-on: https://go-review.googlesource.com/21741 Run-TryBot: Michael Munday Reviewed-by: Brad Fitzpatrick --- src/cmd/link/main.go | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/cmd/link') 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() } } -- cgit v1.3-5-g9baa From 6fee4aa5c76612d133d2b01441e608cfa696bae9 Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Sat, 9 Apr 2016 12:54:45 +1000 Subject: cmd/link/internal: make ld.Bso a *bio.Writer This is a pre requesite of CL 21722 and removes a lot of unidiomatic boilerplate in the linker. Change-Id: If7491b88212b2be7b0c8c588e9c196839131f8ad Reviewed-on: https://go-review.googlesource.com/21780 Run-TryBot: Dave Cheney Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/cmd/link/internal/amd64/asm.go | 16 ++++++------- src/cmd/link/internal/arm/asm.go | 12 +++++----- src/cmd/link/internal/arm64/asm.go | 12 +++++----- src/cmd/link/internal/ld/ar.go | 2 +- src/cmd/link/internal/ld/data.go | 46 ++++++++++++++++++------------------- src/cmd/link/internal/ld/dwarf.go | 2 +- src/cmd/link/internal/ld/ldelf.go | 8 +++---- src/cmd/link/internal/ld/ldpe.go | 2 +- src/cmd/link/internal/ld/lib.go | 34 +++++++++++++-------------- src/cmd/link/internal/ld/pcln.go | 2 +- src/cmd/link/internal/ld/pobj.go | 15 ++++++------ src/cmd/link/internal/mips64/asm.go | 12 +++++----- src/cmd/link/internal/ppc64/asm.go | 12 +++++----- src/cmd/link/internal/s390x/asm.go | 14 +++++------ src/cmd/link/internal/x86/asm.go | 14 +++++------ 15 files changed, 102 insertions(+), 101 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index 2b219da881..8cecd422e1 100644 --- a/src/cmd/link/internal/amd64/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -611,12 +611,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 +634,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,7 +643,7 @@ 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() @@ -688,7 +688,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 { @@ -725,7 +725,7 @@ 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()) } if ld.Linkmode == ld.LinkExternal { @@ -749,7 +749,7 @@ 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()) } case obj.Hdarwin: @@ -760,7 +760,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/arm/asm.go b/src/cmd/link/internal/arm/asm.go index e2718bfac8..b89cb20bdf 100644 --- a/src/cmd/link/internal/arm/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -563,7 +563,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 +581,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,7 +590,7 @@ 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() @@ -613,7 +613,7 @@ 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 { @@ -635,7 +635,7 @@ 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() @@ -669,7 +669,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/asm.go b/src/cmd/link/internal/arm64/asm.go index fd28e8693b..fd8929dd99 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -401,7 +401,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 +419,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,7 +428,7 @@ 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() @@ -451,7 +451,7 @@ 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 { @@ -473,7 +473,7 @@ 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() @@ -507,7 +507,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/ld/ar.go b/src/cmd/link/internal/ld/ar.go index 6a0aeb121f..f9357392d7 100644 --- a/src/cmd/link/internal/ld/ar.go +++ b/src/cmd/link/internal/ld/ar.go @@ -68,7 +68,7 @@ func hostArchive(name string) { 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 } diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index ae430b4e45..cd910b54c0 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -638,7 +638,7 @@ 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() @@ -717,7 +717,7 @@ func dynreloc() { 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() @@ -785,7 +785,7 @@ 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) @@ -816,32 +816,32 @@ func Codeblk(addr int64, size int64) { } if addr < sym.Value { - fmt.Fprintf(&Bso, "%-20s %.8x|", "_", uint64(int64(addr))) + fmt.Fprintf(Bso, "%-20s %.8x|", "_", uint64(int64(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(int64(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(int64(addr))) for ; addr < eaddr; addr++ { - fmt.Fprintf(&Bso, " %.2x", 0) + fmt.Fprintf(Bso, " %.2x", 0) } } @@ -850,7 +850,7 @@ func Codeblk(addr int64, size int64) { 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) @@ -879,26 +879,26 @@ func Datblk(addr int64, size int64) { 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)) + 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, "\n\t%.8x|", uint(addr+int64(-cap(p)+cap(sym.P)))) } - fmt.Fprintf(&Bso, " %.2x", p[0]) + fmt.Fprintf(Bso, " %.2x", p[0]) p = p[1:] } 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") + fmt.Fprintf(Bso, "\n") if Linkmode == LinkExternal { for i = 0; i < int64(len(sym.R)); i++ { @@ -919,20 +919,20 @@ func Datblk(addr int64, size int64) { 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)) + 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 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()) + fmt.Fprintf(Bso, "dwarfblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos()) } blk(dwarfp, addr, size) @@ -1248,7 +1248,7 @@ func dataSort(head *LSym) *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() diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 4741020a6d..de2d50a1a9 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -1931,7 +1931,7 @@ func dwarfgeneratedebugsyms() { } if Debug['v'] != 0 { - fmt.Fprintf(&Bso, "%5.2f dwarf\n", obj.Cputime()) + fmt.Fprintf(Bso, "%5.2f dwarf\n", obj.Cputime()) } // For diagnostic messages. diff --git a/src/cmd/link/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go index 55884c07a2..1c55daa392 100644 --- a/src/cmd/link/internal/ld/ldelf.go +++ b/src/cmd/link/internal/ld/ldelf.go @@ -405,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:] @@ -416,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]) @@ -440,7 +440,7 @@ 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") } } } @@ -449,7 +449,7 @@ func parseArmAttributes(e binary.ByteOrder, data []byte) { 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() diff --git a/src/cmd/link/internal/ld/ldpe.go b/src/cmd/link/internal/ld/ldpe.go index ba5b928ea0..37a550d5c9 100644 --- a/src/cmd/link/internal/ld/ldpe.go +++ b/src/cmd/link/internal/ld/ldpe.go @@ -131,7 +131,7 @@ type PeObj struct { 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 diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index f8cc995c30..e35306dd0e 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -241,7 +241,7 @@ const ( var ( headstring string // buffered output - Bso bio.Writer + Bso *bio.Writer ) // TODO(dfc) outBuf duplicates bio.Writer @@ -469,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) @@ -479,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, "") @@ -489,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) } } @@ -521,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]) } @@ -530,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) } @@ -693,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 { @@ -772,7 +772,7 @@ 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 := bio.Open(lib.File) @@ -1035,7 +1035,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() } @@ -1204,18 +1204,18 @@ 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() } @@ -2007,7 +2007,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() } @@ -2098,7 +2098,7 @@ func callgraph() { 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) } } } diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index 471dda712f..a5fea3db76 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -375,7 +375,7 @@ func pclntab() { 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(), int64(ftab.Size), int64(funcdata_bytes)) } } diff --git a/src/cmd/link/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go index bb48f13185..50066d32d7 100644 --- a/src/cmd/link/internal/ld/pobj.go +++ b/src/cmd/link/internal/ld/pobj.go @@ -46,11 +46,12 @@ var ( ) func Ldmain() { + Bso = bio.BufWriter(os.Stdout) + Ctxt = linknew(SysArch) Ctxt.Diag = Diag - Ctxt.Bso = &Bso + Ctxt.Bso = Bso - Bso = *bio.BufWriter(os.Stdout) Debug = [128]int{} nerrors = 0 outfile = "" @@ -122,7 +123,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 +164,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 +215,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/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go index 9a145e373a..027736cc11 100644 --- a/src/cmd/link/internal/mips64/asm.go +++ b/src/cmd/link/internal/mips64/asm.go @@ -114,7 +114,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() @@ -132,7 +132,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() @@ -141,7 +141,7 @@ 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() @@ -159,7 +159,7 @@ 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 { @@ -178,7 +178,7 @@ 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() @@ -207,7 +207,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/asm.go b/src/cmd/link/internal/ppc64/asm.go index 4c2131dfc6..13d80545c7 100644 --- a/src/cmd/link/internal/ppc64/asm.go +++ b/src/cmd/link/internal/ppc64/asm.go @@ -834,7 +834,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 +852,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,7 +861,7 @@ 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() @@ -879,7 +879,7 @@ 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 { @@ -898,7 +898,7 @@ 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() @@ -927,7 +927,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/asm.go b/src/cmd/link/internal/s390x/asm.go index c5e2d187b8..30b1e5a3e1 100644 --- a/src/cmd/link/internal/s390x/asm.go +++ b/src/cmd/link/internal/s390x/asm.go @@ -505,7 +505,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 +523,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,7 +532,7 @@ 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() @@ -552,7 +552,7 @@ 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.Segdwarf.Fileoff + ld.Segdwarf.Filelen) @@ -560,14 +560,14 @@ func asmb() { 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()) } if ld.Linkmode == ld.LinkExternal { @@ -577,7 +577,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/x86/asm.go b/src/cmd/link/internal/x86/asm.go index 91251de15e..a786ba5a48 100644 --- a/src/cmd/link/internal/x86/asm.go +++ b/src/cmd/link/internal/x86/asm.go @@ -609,7 +609,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 +627,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,7 +636,7 @@ 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() @@ -658,7 +658,7 @@ 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 { @@ -684,7 +684,7 @@ 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() @@ -711,7 +711,7 @@ 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()) } case obj.Hdarwin: @@ -722,7 +722,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) -- cgit v1.3-5-g9baa From ca397bb68e4b548843d2886e374f96ec3bb0f9c0 Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Fri, 8 Apr 2016 19:30:41 +1000 Subject: cmd: remove bio.BufReader and bio.BufWriter bio.BufReader was never used. bio.BufWriter was used to wrap an existing io.Writer, but the bio.Writer returned would not be seekable, so replace all occurences with bufio.Reader instead. Change-Id: I9c6779e35c63178aa4e104c17bb5bb8b52de0359 Reviewed-on: https://go-review.googlesource.com/21722 Reviewed-by: Brad Fitzpatrick Run-TryBot: Dave Cheney TryBot-Result: Gobot Gobot --- src/cmd/asm/internal/asm/endtoend_test.go | 6 +++--- src/cmd/asm/main.go | 15 ++++++++------- src/cmd/compile/internal/gc/bexport.go | 6 +++--- src/cmd/compile/internal/gc/export.go | 4 ++-- src/cmd/compile/internal/gc/go.go | 3 ++- src/cmd/compile/internal/gc/main.go | 3 +-- src/cmd/internal/bio/buf.go | 12 ------------ src/cmd/internal/obj/link.go | 4 ++-- src/cmd/link/internal/ld/lib.go | 2 +- src/cmd/link/internal/ld/link.go | 9 ++++----- src/cmd/link/internal/ld/pobj.go | 4 ++-- 11 files changed, 28 insertions(+), 40 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/asm/internal/asm/endtoend_test.go b/src/cmd/asm/internal/asm/endtoend_test.go index 8986281f10..bc992a7c99 100644 --- a/src/cmd/asm/internal/asm/endtoend_test.go +++ b/src/cmd/asm/internal/asm/endtoend_test.go @@ -5,6 +5,7 @@ package asm import ( + "bufio" "bytes" "fmt" "io/ioutil" @@ -17,7 +18,6 @@ import ( "testing" "cmd/asm/internal/lex" - "cmd/internal/bio" "cmd/internal/obj" ) @@ -34,7 +34,7 @@ func testEndToEnd(t *testing.T, goarch, file string) { pList := obj.Linknewplist(ctxt) var ok bool testOut = new(bytes.Buffer) // The assembler writes test output to this buffer. - ctxt.Bso = bio.BufWriter(os.Stdout) + ctxt.Bso = bufio.NewWriter(os.Stdout) defer ctxt.Bso.Flush() failed := false ctxt.DiagFunc = func(format string, args ...interface{}) { @@ -272,7 +272,7 @@ func testErrors(t *testing.T, goarch, file string) { pList := obj.Linknewplist(ctxt) var ok bool testOut = new(bytes.Buffer) // The assembler writes test output to this buffer. - ctxt.Bso = bio.BufWriter(os.Stdout) + ctxt.Bso = bufio.NewWriter(os.Stdout) defer ctxt.Bso.Flush() failed := false var errBuf bytes.Buffer diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go index 75cb8f75d3..f010ca93f1 100644 --- a/src/cmd/asm/main.go +++ b/src/cmd/asm/main.go @@ -5,6 +5,7 @@ package main import ( + "bufio" "flag" "fmt" "log" @@ -32,11 +33,6 @@ func main() { flags.Parse() - // Create object file, write header. - fd, err := os.Create(*flags.OutputFile) - if err != nil { - log.Fatal(err) - } ctxt := obj.Linknew(architecture.LinkArch) if *flags.PrintOut { ctxt.Debugasm = 1 @@ -46,9 +42,14 @@ func main() { if *flags.Shared || *flags.Dynlink { ctxt.Flag_shared = 1 } - ctxt.Bso = bio.BufWriter(os.Stdout) + ctxt.Bso = bufio.NewWriter(os.Stdout) defer ctxt.Bso.Flush() - output := bio.BufWriter(fd) + + // Create object file, write header. + output, err := bio.Create(*flags.OutputFile) + if err != nil { + log.Fatal(err) + } fmt.Fprintf(output, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion()) fmt.Fprintf(output, "!\n") diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index bb0a34e67b..15e5e3ada6 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -90,9 +90,9 @@ importer. package gc import ( + "bufio" "bytes" "cmd/compile/internal/big" - "cmd/internal/bio" "encoding/binary" "fmt" "sort" @@ -124,7 +124,7 @@ const exportVersion = "v0" const exportInlined = true // default: true type exporter struct { - out *bio.Writer + out *bufio.Writer pkgIndex map[*Pkg]int typIndex map[*Type]int inlined []*Func @@ -136,7 +136,7 @@ type exporter struct { } // export writes the exportlist for localpkg to out and returns the number of bytes written. -func export(out *bio.Writer, trace bool) int { +func export(out *bufio.Writer, trace bool) int { p := exporter{ out: out, pkgIndex: make(map[*Pkg]int), diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go index 2f94b9c62f..dc7c0869bf 100644 --- a/src/cmd/compile/internal/gc/export.go +++ b/src/cmd/compile/internal/gc/export.go @@ -384,7 +384,7 @@ func dumpexport() { if debugFormat { // save a copy of the export data var copy bytes.Buffer - bcopy := bio.BufWriter(©) + bcopy := bufio.NewWriter(©) size = export(bcopy, Debug_export != 0) bcopy.Flush() // flushing to bytes.Buffer cannot fail if n, err := bout.Write(copy.Bytes()); n != size || err != nil { @@ -407,7 +407,7 @@ func dumpexport() { pkgs = savedPkgs pkgMap = savedPkgMap } else { - size = export(bout, Debug_export != 0) + size = export(bout.Writer(), Debug_export != 0) } exportf("\n$$\n") } else { diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index ec7e219d95..d9b28ff8e6 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -5,6 +5,7 @@ package gc import ( + "bufio" "cmd/compile/internal/ssa" "cmd/internal/bio" "cmd/internal/obj" @@ -288,7 +289,7 @@ var Ctxt *obj.Link var writearchive int -var bstdout *bio.Writer +var bstdout *bufio.Writer var Nacl bool diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 03143f5d0a..26acf8861f 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -9,7 +9,6 @@ package gc import ( "bufio" "cmd/compile/internal/ssa" - "cmd/internal/bio" "cmd/internal/obj" "cmd/internal/sys" "flag" @@ -104,7 +103,7 @@ func Main() { Ctxt = obj.Linknew(Thearch.LinkArch) Ctxt.DiagFunc = Yyerror - bstdout = bio.BufWriter(os.Stdout) + bstdout = bufio.NewWriter(os.Stdout) Ctxt.Bso = bstdout localpkg = mkpkg("") diff --git a/src/cmd/internal/bio/buf.go b/src/cmd/internal/bio/buf.go index 0bd4658cdd..983ce46627 100644 --- a/src/cmd/internal/bio/buf.go +++ b/src/cmd/internal/bio/buf.go @@ -51,18 +51,6 @@ func Open(name string) (*Reader, error) { return &Reader{f: f, r: bufio.NewReader(f)}, nil } -// BufWriter returns a Writer on top of w. -// TODO(dfc) remove this method and replace caller with bufio.Writer. -func BufWriter(w io.Writer) *Writer { - return &Writer{w: bufio.NewWriter(w)} -} - -// BufWriter returns a Reader on top of r. -// TODO(dfc) remove this method and replace caller with bufio.Reader. -func BufReader(r io.Reader) *Reader { - return &Reader{r: bufio.NewReader(r)} -} - func (w *Writer) Write(p []byte) (int, error) { return w.w.Write(p) } diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index c48c3d807f..62175f9ed8 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -31,7 +31,7 @@ package obj import ( - "cmd/internal/bio" + "bufio" "cmd/internal/sys" ) @@ -629,7 +629,7 @@ type Link struct { Flag_shared int32 Flag_dynlink bool Flag_optimize bool - Bso *bio.Writer + Bso *bufio.Writer Pathname string Goroot string Goroot_final string diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index e35306dd0e..01dca9fc31 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -241,7 +241,7 @@ const ( var ( headstring string // buffered output - Bso *bio.Writer + Bso *bufio.Writer ) // TODO(dfc) outBuf duplicates bio.Writer diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index cbcc979c85..52b52f1cc0 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -31,7 +31,7 @@ package ld import ( - "cmd/internal/bio" + "bufio" "cmd/internal/sys" "debug/elf" "fmt" @@ -165,10 +165,9 @@ type Link struct { Headtype int Arch *sys.Arch Debugvlog int32 - - Bso *bio.Writer - Windows int32 - Goroot string + Bso *bufio.Writer + Windows int32 + Goroot string // Symbol lookup based on name and indexed by version. Hash []map[string]*LSym diff --git a/src/cmd/link/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go index 50066d32d7..f4fb4d4845 100644 --- a/src/cmd/link/internal/ld/pobj.go +++ b/src/cmd/link/internal/ld/pobj.go @@ -31,7 +31,7 @@ package ld import ( - "cmd/internal/bio" + "bufio" "cmd/internal/obj" "cmd/internal/sys" "flag" @@ -46,7 +46,7 @@ var ( ) func Ldmain() { - Bso = bio.BufWriter(os.Stdout) + Bso = bufio.NewWriter(os.Stdout) Ctxt = linknew(SysArch) Ctxt.Diag = Diag -- cgit v1.3-5-g9baa From 93368be61ebaf8069d0d70034097de580441c412 Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Fri, 8 Apr 2016 20:37:54 +1000 Subject: cmd/internal/bio: embed bufio.{Reader,Writer} in bio.{Reader,Writer} Change-Id: Ie95b0b0d4f724f4769cf2d4f8063cb5019fa9bc9 Reviewed-on: https://go-review.googlesource.com/21781 Reviewed-by: Brad Fitzpatrick --- src/cmd/compile/internal/gc/export.go | 2 +- src/cmd/internal/bio/buf.go | 56 ++++++++--------------------------- src/cmd/internal/obj/objfile.go | 2 +- src/cmd/link/internal/ld/objfile.go | 2 +- 4 files changed, 16 insertions(+), 46 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go index dc7c0869bf..ae36657a65 100644 --- a/src/cmd/compile/internal/gc/export.go +++ b/src/cmd/compile/internal/gc/export.go @@ -407,7 +407,7 @@ func dumpexport() { pkgs = savedPkgs pkgMap = savedPkgMap } else { - size = export(bout.Writer(), Debug_export != 0) + size = export(bout.Writer, Debug_export != 0) } exportf("\n$$\n") } else { diff --git a/src/cmd/internal/bio/buf.go b/src/cmd/internal/bio/buf.go index 983ce46627..564ac77cbf 100644 --- a/src/cmd/internal/bio/buf.go +++ b/src/cmd/internal/bio/buf.go @@ -17,21 +17,15 @@ const EOF = -1 // Reader implements a seekable buffered io.Reader. type Reader struct { f *os.File - r *bufio.Reader + *bufio.Reader } // Writer implements a seekable buffered io.Writer. type Writer struct { f *os.File - w *bufio.Writer + *bufio.Writer } -// Reader returns this Reader's underlying bufio.Reader. -func (r *Reader) Reader() *bufio.Reader { return r.r } - -// Writer returns this Writer's underlying bufio.Writer. -func (w *Writer) Writer() *bufio.Writer { return w.w } - // Create creates the file named name and returns a Writer // for that file. func Create(name string) (*Writer, error) { @@ -39,7 +33,7 @@ func Create(name string) (*Writer, error) { if err != nil { return nil, err } - return &Writer{f: f, w: bufio.NewWriter(f)}, nil + return &Writer{f: f, Writer: bufio.NewWriter(f)}, nil } // Open returns a Reader for the file named name. @@ -48,31 +42,23 @@ func Open(name string) (*Reader, error) { if err != nil { return nil, err } - return &Reader{f: f, r: bufio.NewReader(f)}, nil -} - -func (w *Writer) Write(p []byte) (int, error) { - return w.w.Write(p) -} - -func (w *Writer) WriteString(p string) (int, error) { - return w.w.WriteString(p) + return &Reader{f: f, Reader: bufio.NewReader(f)}, nil } func (r *Reader) Seek(offset int64, whence int) int64 { if whence == 1 { - offset -= int64(r.r.Buffered()) + offset -= int64(r.Buffered()) } off, err := r.f.Seek(offset, whence) if err != nil { log.Fatalf("seeking in output: %v", err) } - r.r.Reset(r.f) + r.Reset(r.f) return off } func (w *Writer) Seek(offset int64, whence int) int64 { - if err := w.w.Flush(); err != nil { + if err := w.Flush(); err != nil { log.Fatalf("writing output: %v", err) } off, err := w.f.Seek(offset, whence) @@ -87,12 +73,12 @@ func (r *Reader) Offset() int64 { if err != nil { log.Fatalf("seeking in output [0, 1]: %v", err) } - off -= int64(r.r.Buffered()) + off -= int64(r.Buffered()) return off } func (w *Writer) Offset() int64 { - if err := w.w.Flush(); err != nil { + if err := w.Flush(); err != nil { log.Fatalf("writing output: %v", err) } off, err := w.f.Seek(0, 1) @@ -102,16 +88,8 @@ func (w *Writer) Offset() int64 { return off } -func (w *Writer) Flush() error { - return w.w.Flush() -} - -func (w *Writer) WriteByte(c byte) error { - return w.w.WriteByte(c) -} - func Bread(r *Reader, p []byte) int { - n, err := io.ReadFull(r.r, p) + n, err := io.ReadFull(r, p) if n == 0 { if err != nil && err != io.EOF { n = -1 @@ -121,7 +99,7 @@ func Bread(r *Reader, p []byte) int { } func Bgetc(r *Reader) int { - c, err := r.r.ReadByte() + c, err := r.ReadByte() if err != nil { if err != io.EOF { log.Fatalf("reading input: %v", err) @@ -131,16 +109,8 @@ func Bgetc(r *Reader) int { return int(c) } -func (r *Reader) Read(p []byte) (int, error) { - return r.r.Read(p) -} - -func (r *Reader) Peek(n int) ([]byte, error) { - return r.r.Peek(n) -} - func Brdline(r *Reader, delim int) string { - s, err := r.r.ReadBytes(byte(delim)) + s, err := r.ReadBytes(byte(delim)) if err != nil { log.Fatalf("reading input: %v", err) } @@ -152,7 +122,7 @@ func (r *Reader) Close() error { } func (w *Writer) Close() error { - err := w.w.Flush() + err := w.Flush() err1 := w.f.Close() if err == nil { err = err1 diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index ed6d75eba3..ee21f39d10 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -377,7 +377,7 @@ func (w *objWriter) writeLengths() { func newObjWriter(ctxt *Link, b *bio.Writer) *objWriter { return &objWriter{ ctxt: ctxt, - wr: b.Writer(), + wr: b.Writer, vrefIdx: make(map[string]int), refIdx: make(map[string]int), } diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go index 61a67cf94c..578afd4c74 100644 --- a/src/cmd/link/internal/ld/objfile.go +++ b/src/cmd/link/internal/ld/objfile.go @@ -150,7 +150,7 @@ type objReader struct { 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, -- cgit v1.3-5-g9baa From bce9747ed00c53e7ddeea102e87aede1b3ec9bd3 Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Sat, 9 Apr 2016 15:04:45 +1000 Subject: cmd: remove unused code Generated with honnef.co/go/unused There is a large amount of unused code in cmd/internal/obj/s390x but that can wait til the s390x port is merged. There is some unused code in cmd/internal/unvendor/golang.org/x/arch/arm/armasm but that should be addressed upstream and a new revision imported. Change-Id: I252c0f9ea8c5bb1a0b530a374ef13a0a20ea56aa Reviewed-on: https://go-review.googlesource.com/21782 Reviewed-by: Brad Fitzpatrick Run-TryBot: Dave Cheney --- src/cmd/internal/goobj/read.go | 7 ++---- src/cmd/internal/obj/mips/asm0.go | 4 ---- src/cmd/internal/obj/x86/asm6.go | 5 ----- src/cmd/internal/obj/x86/obj6_test.go | 1 - src/cmd/internal/objfile/pe.go | 2 -- src/cmd/link/internal/amd64/asm.go | 6 ----- src/cmd/link/internal/arm/asm.go | 5 ----- src/cmd/link/internal/arm64/asm.go | 4 ---- src/cmd/link/internal/ld/data.go | 4 ---- src/cmd/link/internal/ld/deadcode.go | 4 +--- src/cmd/link/internal/ld/decodesym.go | 18 --------------- src/cmd/link/internal/ld/go.go | 30 +------------------------ src/cmd/link/internal/ld/macho.go | 7 ++---- src/cmd/link/internal/ld/macho_combine_dwarf.go | 4 +--- src/cmd/link/internal/mips64/asm.go | 4 ---- src/cmd/link/internal/ppc64/asm.go | 4 ---- src/cmd/link/internal/x86/asm.go | 4 ---- 17 files changed, 7 insertions(+), 106 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/internal/goobj/read.go b/src/cmd/internal/goobj/read.go index 5434661384..698d58efe0 100644 --- a/src/cmd/internal/goobj/read.go +++ b/src/cmd/internal/goobj/read.go @@ -229,11 +229,8 @@ var ( errCorruptArchive = errors.New("corrupt archive") errTruncatedArchive = errors.New("truncated archive") - errNotArchive = errors.New("unrecognized archive format") - - errCorruptObject = errors.New("corrupt object file") - errTruncatedObject = errors.New("truncated object file") - errNotObject = errors.New("unrecognized object file format") + errCorruptObject = errors.New("corrupt object file") + errNotObject = errors.New("unrecognized object file format") ) // An objReader is an object file reader. diff --git a/src/cmd/internal/obj/mips/asm0.go b/src/cmd/internal/obj/mips/asm0.go index 521cb66dec..5cb5d1cfd9 100644 --- a/src/cmd/internal/obj/mips/asm0.go +++ b/src/cmd/internal/obj/mips/asm0.go @@ -974,10 +974,6 @@ func OP_JMP(op uint32, i uint32) uint32 { return op | i&0x3FFFFFF } -func oclass(a *obj.Addr) int { - return int(a.Class) - 1 -} - func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) { o1 := uint32(0) o2 := uint32(0) diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index b940094b8b..c15b59b5e8 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -884,11 +884,6 @@ var yvex_vpbroadcast = []ytab{ {Yxm, Ynone, Yyr, Zvex_rm_v_r, 2}, } -var yvex_xxmyxm = []ytab{ - {Yxr, Ynone, Yxm, Zvex_r_v_rm, 2}, - {Yyr, Ynone, Yxm, Zvex_r_v_rm, 2}, -} - var ymmxmm0f38 = []ytab{ {Ymm, Ynone, Ymr, Zlitm_r, 3}, {Yxm, Ynone, Yxr, Zlitm_r, 5}, diff --git a/src/cmd/internal/obj/x86/obj6_test.go b/src/cmd/internal/obj/x86/obj6_test.go index a5c80cea3b..fe1f95cc0d 100644 --- a/src/cmd/internal/obj/x86/obj6_test.go +++ b/src/cmd/internal/obj/x86/obj6_test.go @@ -76,7 +76,6 @@ func parseTestData(t *testing.T) *ParsedTestData { } var spaces_re *regexp.Regexp = regexp.MustCompile("\\s+") -var marker_re *regexp.Regexp = regexp.MustCompile("MOVQ \\$([0-9]+), AX") func normalize(s string) string { return spaces_re.ReplaceAllLiteralString(strings.TrimSpace(s), " ") diff --git a/src/cmd/internal/objfile/pe.go b/src/cmd/internal/objfile/pe.go index 1b319941ac..c024762371 100644 --- a/src/cmd/internal/objfile/pe.go +++ b/src/cmd/internal/objfile/pe.go @@ -69,8 +69,6 @@ func (f *peFile) symbols() ([]Sym, error) { text = 0x20 data = 0x40 bss = 0x80 - permX = 0x20000000 - permR = 0x40000000 permW = 0x80000000 ) ch := sect.Characteristics diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index 8cecd422e1..a6dce6c2c9 100644 --- a/src/cmd/link/internal/amd64/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -99,12 +99,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 diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go index b89cb20bdf..1188615716 100644 --- a/src/cmd/link/internal/arm/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -114,11 +114,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 diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index fd8929dd99..d3ba5ff3f3 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -91,10 +91,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") } diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index cd910b54c0..2c8cc9ca4f 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -236,10 +236,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 } diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index b17b96001e..8b2d0d447e 100644 --- a/src/cmd/link/internal/ld/deadcode.go +++ b/src/cmd/link/internal/ld/deadcode.go @@ -170,9 +170,7 @@ type methodref struct { r [3]*Reloc // R_METHOD 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 { diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index bc29938590..1066d220f7 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -56,11 +56,6 @@ func decodetype_kind(s *LSym) uint8 { return uint8(s.P[2*SysArch.PtrSize+7] & obj.KindMask) // 0x13 / 0x1f } -// Type.commonType.kind -func decodetype_noptr(s *LSym) uint8 { - return uint8(s.P[2*SysArch.PtrSize+7] & obj.KindNoPointers) // 0x13 / 0x1f -} - // Type.commonType.kind func decodetype_usegcprog(s *LSym) uint8 { return uint8(s.P[2*SysArch.PtrSize+7] & obj.KindGCProg) // 0x13 / 0x1f @@ -216,19 +211,6 @@ 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 "" - } - strlen := int64(decode_inuxi(s.P[SysArch.PtrSize:], SysArch.IntSize)) - return string(r.Sym.P[r.Add : r.Add+strlen]) -} - // decodetype_name decodes the name from a reflect.name. func decodetype_name(s *LSym, off int) string { r := decode_reloc(s, int32(off)) diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go index 5dad90dae6..3af5f7a046 100644 --- a/src/cmd/link/internal/ld/go.go +++ b/src/cmd/link/internal/ld/go.go @@ -419,35 +419,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/macho.go b/src/cmd/link/internal/ld/macho.go index 25d48fbf22..1d9a1a9324 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -586,11 +586,8 @@ 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 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/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go index 027736cc11..ad6a1f7524 100644 --- a/src/cmd/link/internal/mips64/asm.go +++ b/src/cmd/link/internal/mips64/asm.go @@ -41,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") } diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go index 13d80545c7..3970f3c5f9 100644 --- a/src/cmd/link/internal/ppc64/asm.go +++ b/src/cmd/link/internal/ppc64/asm.go @@ -265,10 +265,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 diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go index a786ba5a48..19a8917ec8 100644 --- a/src/cmd/link/internal/x86/asm.go +++ b/src/cmd/link/internal/x86/asm.go @@ -139,10 +139,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 -- cgit v1.3-5-g9baa From 9d4efdfd12f47f1ed8ce482ebeeb4d4e30a2dbc6 Mon Sep 17 00:00:00 2001 From: Dave Cheney Date: Fri, 8 Apr 2016 20:44:56 +1000 Subject: cmd/internal/bio: move Bgetc to link/internal/ld Also, remove bio.Brdline. Change-Id: I3e0caed27a373fd71737cf6892de5e8fc208b776 Reviewed-on: https://go-review.googlesource.com/21783 Reviewed-by: Brad Fitzpatrick Run-TryBot: Dave Cheney --- src/cmd/internal/bio/buf.go | 21 --------------------- src/cmd/link/internal/ld/lib.go | 33 ++++++++++++++++++++++----------- 2 files changed, 22 insertions(+), 32 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/internal/bio/buf.go b/src/cmd/internal/bio/buf.go index 564ac77cbf..6a5d821d45 100644 --- a/src/cmd/internal/bio/buf.go +++ b/src/cmd/internal/bio/buf.go @@ -12,8 +12,6 @@ import ( "os" ) -const EOF = -1 - // Reader implements a seekable buffered io.Reader. type Reader struct { f *os.File @@ -98,25 +96,6 @@ func Bread(r *Reader, p []byte) int { return n } -func Bgetc(r *Reader) int { - c, err := r.ReadByte() - if err != nil { - if err != io.EOF { - log.Fatalf("reading input: %v", err) - } - return EOF - } - return int(c) -} - -func Brdline(r *Reader, delim int) string { - s, err := r.ReadBytes(byte(delim)) - if err != nil { - log.Fatalf("reading input: %v", err) - } - return string(s) -} - func (r *Reader) Close() error { return r.f.Close() } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 01dca9fc31..6e33ec3b05 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1269,10 +1269,10 @@ func ldobj(f *bio.Reader, pkg string, length int64, pn string, file string, when eof := f.Offset() + length start := f.Offset() - c1 := bio.Bgetc(f) - c2 := bio.Bgetc(f) - c3 := bio.Bgetc(f) - c4 := bio.Bgetc(f) + 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) @@ -1289,9 +1289,9 @@ func ldobj(f *bio.Reader, pkg string, length int64, pn string, file string, when } /* check the header */ - line := bio.Brdline(f, '\n') - if line == "" { - Diag("truncated object file: %s", pn) + line, err := f.ReadString('\n') + if err != nil { + Diag("truncated object file: %s: %v", pn, err) return nil } @@ -1336,13 +1336,13 @@ func ldobj(f *bio.Reader, pkg string, length int64, pn string, file string, when import0 := f.Offset() c1 = '\n' // the last line ended in \n - c2 = bio.Bgetc(f) - c3 = bio.Bgetc(f) + c2 = bgetc(f) + c3 = bgetc(f) for c1 != '\n' || c2 != '!' || c3 != '\n' { c1 = c2 c2 = c3 - c3 = bio.Bgetc(f) - if c3 == bio.EOF { + c3 = bgetc(f) + if c3 == -1 { Diag("truncated object file: %s", pn) return nil } @@ -2133,3 +2133,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) +} -- cgit v1.3-5-g9baa From de7ee57c7ead59899d5b412a839c995de0e813b5 Mon Sep 17 00:00:00 2001 From: Marvin Stenger Date: Fri, 8 Apr 2016 18:19:10 +0200 Subject: cmd: remove bio.Bread Replace calls to bio.Bread with calls to io.ReadFull. Change-Id: I2ee8739d01e04a4da9c20b6ce7d1d5b89914b8ad Reviewed-on: https://go-review.googlesource.com/21750 Reviewed-by: Dave Cheney --- src/cmd/internal/bio/buf.go | 11 ----------- src/cmd/link/internal/ld/ar.go | 10 +++++----- src/cmd/link/internal/ld/go.go | 3 ++- src/cmd/link/internal/ld/ldelf.go | 10 ++++++---- src/cmd/link/internal/ld/ldmacho.go | 34 +++++++++++++++++++++++++--------- src/cmd/link/internal/ld/ldpe.go | 14 +++++++++----- src/cmd/link/internal/ld/lib.go | 21 +++++++++++++-------- 7 files changed, 60 insertions(+), 43 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/internal/bio/buf.go b/src/cmd/internal/bio/buf.go index 6a5d821d45..7a077041c2 100644 --- a/src/cmd/internal/bio/buf.go +++ b/src/cmd/internal/bio/buf.go @@ -7,7 +7,6 @@ package bio import ( "bufio" - "io" "log" "os" ) @@ -86,16 +85,6 @@ func (w *Writer) Offset() int64 { return off } -func Bread(r *Reader, p []byte) int { - n, err := io.ReadFull(r, p) - if n == 0 { - if err != nil && err != io.EOF { - n = -1 - } - } - return n -} - func (r *Reader) Close() error { return r.f.Close() } diff --git a/src/cmd/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go index f9357392d7..323dfbefc5 100644 --- a/src/cmd/link/internal/ld/ar.go +++ b/src/cmd/link/internal/ld/ar.go @@ -35,6 +35,7 @@ import ( "cmd/internal/obj" "encoding/binary" "fmt" + "io" "os" ) @@ -76,8 +77,8 @@ func hostArchive(name string) { } defer f.Close() - magbuf := make([]byte, len(ARMAG)) - if bio.Bread(f, magbuf) != len(magbuf) { + var magbuf [len(ARMAG)]byte + if _, err := io.ReadFull(f, magbuf[:]); err != nil { Exitf("file %s too short", name) } @@ -138,9 +139,8 @@ func readArmap(filename string, f *bio.Reader, arhdr ArHdr) archiveMap { wordSize = 8 } - l := atolwhex(arhdr.size) - contents := make([]byte, l) - if bio.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/go.go b/src/cmd/link/internal/ld/go.go index 3af5f7a046..425c75571f 100644 --- a/src/cmd/link/internal/ld/go.go +++ b/src/cmd/link/internal/ld/go.go @@ -11,6 +11,7 @@ import ( "cmd/internal/bio" "cmd/internal/obj" "fmt" + "io" "os" "strings" ) @@ -49,7 +50,7 @@ func ldpkg(f *bio.Reader, pkg string, length int64, filename string, whence int) } bdata := make([]byte, length) - if int64(bio.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() diff --git a/src/cmd/link/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go index 1c55daa392..d9581a5189 100644 --- a/src/cmd/link/internal/ld/ldelf.go +++ b/src/cmd/link/internal/ld/ldelf.go @@ -476,7 +476,7 @@ func ldelf(f *bio.Reader, pkg string, length int64, pn string) { var sect *ElfSect var sym ElfSym var symbols []*LSym - if bio.Bread(f, hdrbuf[:]) != len(hdrbuf) { + if _, err := io.ReadFull(f, hdrbuf[:]); err != nil { goto bad } hdr = new(ElfHdrBytes) @@ -986,9 +986,11 @@ func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) { } sect.base = make([]byte, sect.size) - err = fmt.Errorf("short read") - if elfobj.f.Seek(int64(uint64(elfobj.base)+sect.off), 0) < 0 || bio.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 diff --git a/src/cmd/link/internal/ld/ldmacho.go b/src/cmd/link/internal/ld/ldmacho.go index dffe6f69ce..8dc4033bbc 100644 --- a/src/cmd/link/internal/ld/ldmacho.go +++ b/src/cmd/link/internal/ld/ldmacho.go @@ -6,6 +6,7 @@ import ( "cmd/internal/sys" "encoding/binary" "fmt" + "io" "log" "sort" ) @@ -299,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 m.f.Seek(m.base+int64(sect.reloff), 0) < 0 || bio.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 @@ -345,7 +349,10 @@ func macholoaddsym(m *LdMachoObj, d *LdMachoDysymtab) int { n := int(d.nindirectsyms) p := make([]byte, n*4) - if m.f.Seek(m.base+int64(d.indirectsymoff), 0) < 0 || bio.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 } @@ -362,7 +369,10 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int { } strbuf := make([]byte, symtab.strsize) - if m.f.Seek(m.base+int64(symtab.stroff), 0) < 0 || bio.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 } @@ -372,7 +382,10 @@ func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int { } n := int(symtab.nsym * uint32(symsize)) symbuf := make([]byte, n) - if m.f.Seek(m.base+int64(symtab.symoff), 0) < 0 || bio.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) @@ -433,7 +446,7 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) { Ctxt.IncVersion() base := f.Offset() - if bio.Bread(f, hdr[:]) != len(hdr) { + if _, err := io.ReadFull(f, hdr[:]); err != nil { goto bad } @@ -455,8 +468,7 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) { } if is64 { - var tmp [4]uint8 - bio.Bread(f, tmp[:4]) // skip reserved word in header + f.Seek(4, 1) // skip reserved word in header } m = new(LdMachoObj) @@ -494,7 +506,7 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) { m.cmd = make([]LdMachoCmd, ncmd) off = uint32(len(hdr)) cmdp = make([]byte, cmdsz) - if bio.Bread(f, cmdp) != len(cmdp) { + if _, err2 := io.ReadFull(f, cmdp); err2 != nil { err = fmt.Errorf("reading cmds: %v", err) goto bad } @@ -557,7 +569,11 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) { } dat = make([]byte, c.seg.filesz) - if f.Seek(m.base+int64(c.seg.fileoff), 0) < 0 || bio.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 } diff --git a/src/cmd/link/internal/ld/ldpe.go b/src/cmd/link/internal/ld/ldpe.go index 37a550d5c9..7f7121ff94 100644 --- a/src/cmd/link/internal/ld/ldpe.go +++ b/src/cmd/link/internal/ld/ldpe.go @@ -10,6 +10,7 @@ import ( "cmd/internal/sys" "encoding/binary" "fmt" + "io" "log" "sort" "strconv" @@ -176,13 +177,13 @@ func ldpe(f *bio.Reader, pkg string, length int64, pn string) { // load string table f.Seek(int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0) - if bio.Bread(f, symbuf[:4]) != 4 { + if _, err := io.ReadFull(f, symbuf[:4]); err != nil { goto bad } l = Le32(symbuf[:]) peobj.snames = make([]byte, l) f.Seek(int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0) - if bio.Bread(f, peobj.snames) != len(peobj.snames) { + if _, err := io.ReadFull(f, peobj.snames); err != nil { goto bad } @@ -205,7 +206,7 @@ func ldpe(f *bio.Reader, pkg string, length int64, pn string) { f.Seek(int64(base)+int64(peobj.fh.PointerToSymbolTable), 0) for i := 0; uint32(i) < peobj.fh.NumberOfSymbols; i += numaux + 1 { f.Seek(int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0) - if bio.Bread(f, symbuf[:]) != len(symbuf) { + if _, err := io.ReadFull(f, symbuf[:]); err != nil { goto bad } @@ -293,7 +294,7 @@ func ldpe(f *bio.Reader, pkg string, length int64, pn string) { f.Seek(int64(peobj.base)+int64(rsect.sh.PointerToRelocations), 0) for j = 0; j < int(rsect.sh.NumberOfRelocations); j++ { rp = &r[j] - if bio.Bread(f, symbuf[:10]) != 10 { + if _, err := io.ReadFull(f, symbuf[:10]); err != nil { goto bad } rva := Le32(symbuf[0:]) @@ -466,7 +467,10 @@ func pemap(peobj *PeObj, sect *PeSect) int { if sect.sh.PointerToRawData == 0 { // .bss doesn't have data in object file return 0 } - if peobj.f.Seek(int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 || bio.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 } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 6e33ec3b05..1f2df8b9c5 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -745,12 +745,12 @@ func nextar(bp *bio.Reader, off int64, a *ArHdr) int64 { off++ } bp.Seek(off, 0) - buf := make([]byte, SAR_HDR) - if n := bio.Bread(bp, buf); n < len(buf) { - if n >= 0 { - return 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]) @@ -780,8 +780,11 @@ func objfile(lib *Library) { Exitf("cannot open file %s: %v", lib.File, err) } - magbuf := make([]byte, len(ARMAG)) - if bio.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 := f.Seek(0, 2) @@ -811,7 +814,9 @@ func objfile(lib *Library) { if Buildmode == BuildmodeShared { before := f.Offset() pkgdefBytes := make([]byte, atolwhex(arhdr.size)) - bio.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[:] f.Seek(before, 0) -- cgit v1.3-5-g9baa From 4f12cc08132f3e5d2ba4b756c91d88c2e58a73b1 Mon Sep 17 00:00:00 2001 From: Shahar Kohanim Date: Thu, 7 Apr 2016 18:00:57 +0300 Subject: cmd/link: symbol generation optimizations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After making dwarf generation backed by LSyms there was a performance regression of about 10%. These changes make on the fly symbol generation faster and are meant to help mitigate that. name old secs new secs delta LinkCmdGo 0.55 ± 9% 0.53 ± 8% -4.42% (p=0.000 n=100+99) name old MaxRSS new MaxRSS delta LinkCmdGo 152k ± 6% 149k ± 3% -1.99% (p=0.000 n=99+97) Change-Id: Iacca3ec924ce401aa83126bc0b10fe89bedf0ba6 Reviewed-on: https://go-review.googlesource.com/21733 Run-TryBot: Shahar Kohanim TryBot-Result: Gobot Gobot Reviewed-by: David Crawshaw --- src/cmd/link/internal/ld/data.go | 32 ++++++++++++++++++-------------- src/cmd/link/internal/ld/dwarf.go | 13 +++++++++---- src/cmd/link/internal/ld/pcln.go | 3 +-- src/cmd/link/internal/ld/symtab.go | 10 ++-------- 4 files changed, 30 insertions(+), 28 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 2c8cc9ca4f..ae7c287f59 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -50,8 +50,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] } @@ -90,11 +91,8 @@ func Addbytes(ctxt *Link, s *LSym, bytes []byte) int64 { s.Type = obj.SDATA } s.Attr |= AttrReachable - s.Size += int64(len(bytes)) - if int64(int(s.Size)) != s.Size { - log.Fatalf("Addbytes size %d too long", s.Size) - } s.P = append(s.P, bytes...) + s.Size = int64(len(s.P)) return s.Size } @@ -106,7 +104,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 { @@ -1006,16 +1012,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 diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index de2d50a1a9..a3a931f94c 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -88,9 +88,7 @@ func uleb128put(s *LSym, v int64) { func sleb128put(s *LSym, v int64) { b := appendSleb128(encbuf[:0], v) - for _, x := range b { - Adduint8(Ctxt, s, x) - } + Addbytes(Ctxt, s, b) } /* @@ -552,8 +550,15 @@ func findchild(die *DWDie, name string) *DWDie { return nil } +// Used to avoid string allocation when looking up dwarf symbols +var prefixBuf = []byte(infoprefix) + func find(name string) *LSym { - return Linkrlookup(Ctxt, infoprefix+name, 0) + 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 { diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index a5fea3db76..9a947c7c07 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -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))) } diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index ecd5c741bb..c7c2733507 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -54,15 +54,9 @@ 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 } -- cgit v1.3-5-g9baa From e79fef8e55f8a893c65f41566bbec10339d45dec Mon Sep 17 00:00:00 2001 From: Shawn Walker-Salas Date: Thu, 7 Apr 2016 15:26:57 -0700 Subject: cmd/link: external linking can fail on Solaris 11.2+ Workaround external linking issues encountered on Solaris 11.2+ due to the go.o object file being created with a NULL STT_FILE symtab entry by using a placeholder name. Fixes #14957 Change-Id: I89c501b4c548469f3c878151947d35588057982b Reviewed-on: https://go-review.googlesource.com/21636 Reviewed-by: David Crawshaw --- src/cmd/link/internal/ld/symtab.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index c7c2733507..ae0b17c259 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -198,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 -- cgit v1.3-5-g9baa From e07a4459a155789fb57bbf4e2c8eaca5b369fd17 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Tue, 12 Apr 2016 12:16:20 -0700 Subject: cmd: replace x[i:][0] expressions with x[i] Passes toolstash -cmp. Change-Id: Id504e71ed1f23900e24a9aed25143c94f4d7d50c Reviewed-on: https://go-review.googlesource.com/21899 Run-TryBot: Matthew Dempsky Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/cmd/internal/obj/arm64/asm7.go | 2 +- src/cmd/internal/obj/mips/asm0.go | 2 +- src/cmd/internal/obj/s390x/asmz.go | 2 +- src/cmd/internal/obj/x86/asm6.go | 3 +-- src/cmd/link/internal/ld/decodesym.go | 4 ++-- src/cmd/link/internal/ld/ldelf.go | 2 +- 6 files changed, 7 insertions(+), 8 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index ff8d4fdf60..d0ae6115cb 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -1087,7 +1087,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int { func oplook(ctxt *obj.Link, p *obj.Prog) *Optab { a1 := int(p.Optab) if a1 != 0 { - return &optab[a1-1:][0] + return &optab[a1-1] } a1 = int(p.From.Class) if a1 == 0 { diff --git a/src/cmd/internal/obj/mips/asm0.go b/src/cmd/internal/obj/mips/asm0.go index 5cb5d1cfd9..13e7600c21 100644 --- a/src/cmd/internal/obj/mips/asm0.go +++ b/src/cmd/internal/obj/mips/asm0.go @@ -611,7 +611,7 @@ func oplook(ctxt *obj.Link, p *obj.Prog) *Optab { a1 := int(p.Optab) if a1 != 0 { - return &optab[a1-1:][0] + return &optab[a1-1] } a1 = int(p.From.Class) if a1 == 0 { diff --git a/src/cmd/internal/obj/s390x/asmz.go b/src/cmd/internal/obj/s390x/asmz.go index cf3b11424b..bae4dc3ce7 100644 --- a/src/cmd/internal/obj/s390x/asmz.go +++ b/src/cmd/internal/obj/s390x/asmz.go @@ -606,7 +606,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int { func oplook(ctxt *obj.Link, p *obj.Prog) *Optab { a1 := int(p.Optab) if a1 != 0 { - return &optab[a1-1:][0] + return &optab[a1-1] } a1 = int(p.From.Class) if a1 == 0 { diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index c15b59b5e8..c563a7a48d 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -4452,9 +4452,8 @@ func asmins(ctxt *obj.Link, p *obj.Prog) { } n := ctxt.AsmBuf.Len() - var r *obj.Reloc for i := len(ctxt.Cursym.R) - 1; i >= 0; i-- { - r = &ctxt.Cursym.R[i:][0] + r := &ctxt.Cursym.R[i] if int64(r.Off) < p.Pc { break } diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index 1066d220f7..7daa8bc812 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -17,9 +17,9 @@ import ( // ../gc/reflect.c stuffs in these. 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 diff --git a/src/cmd/link/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go index d9581a5189..d07a2a2c34 100644 --- a/src/cmd/link/internal/ld/ldelf.go +++ b/src/cmd/link/internal/ld/ldelf.go @@ -774,7 +774,7 @@ func ldelf(f *bio.Reader, 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 -- cgit v1.3-5-g9baa From f028b9f9e2433662502283850d06e9e07e72a6bb Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Sun, 27 Mar 2016 10:21:48 -0400 Subject: cmd/link, etc: store typelinks as offsets This is the first in a series of CLs to replace the use of pointers in binary read-only data with offsets. In standard Go binaries these CLs have a small effect, shrinking 8-byte pointers to 4-bytes. In position-independent code, it also saves the dynamic relocation for the pointer. This has a significant effect on the binary size when building as PIE, c-archive, or c-shared. darwin/amd64: cmd/go: -12KB (0.1%) jujud: -82KB (0.1%) linux/amd64 PIE: cmd/go: -86KB (0.7%) jujud: -569KB (0.7%) For #6853. Change-Id: Iad5625bbeba58dabfd4d334dbee3fcbfe04b2dcf Reviewed-on: https://go-review.googlesource.com/21284 Reviewed-by: Ian Lance Taylor Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/go.go | 2 -- src/cmd/compile/internal/gc/main.go | 4 --- src/cmd/compile/internal/gc/obj.go | 6 +++++ src/cmd/compile/internal/gc/reflect.go | 17 +++++------- src/cmd/internal/obj/data.go | 21 ++++++++++++++- src/cmd/internal/obj/link.go | 3 +++ src/cmd/link/internal/ld/data.go | 18 +++++++++++++ src/cmd/link/internal/ld/symtab.go | 4 +++ src/reflect/export_test.go | 8 +++--- src/reflect/type.go | 47 ++++++++++++++++++++++------------ src/runtime/runtime1.go | 8 +++--- src/runtime/symtab.go | 3 ++- 12 files changed, 99 insertions(+), 42 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index d9b28ff8e6..5df49b56d6 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -171,8 +171,6 @@ var msanpkg *Pkg // package runtime/msan var typepkg *Pkg // fake package for runtime type info (headers) -var typelinkpkg *Pkg // fake package for runtime type info (data) - var unsafepkg *Pkg // package unsafe var trackpkg *Pkg // fake package for field tracking diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 26acf8861f..45a510d577 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -126,10 +126,6 @@ func Main() { itabpkg.Name = "go.itab" itabpkg.Prefix = "go.itab" // not go%2eitab - typelinkpkg = mkpkg("go.typelink") - typelinkpkg.Name = "go.typelink" - typelinkpkg.Prefix = "go.typelink" // not go%2etypelink - itablinkpkg = mkpkg("go.itablink") itablinkpkg.Name = "go.itablink" itablinkpkg.Prefix = "go.itablink" // not go%2eitablink diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go index 23c8be645c..eed0ed6e24 100644 --- a/src/cmd/compile/internal/gc/obj.go +++ b/src/cmd/compile/internal/gc/obj.go @@ -321,6 +321,12 @@ func dsymptrLSym(s *obj.LSym, off int, x *obj.LSym, xoff int) int { return off } +func dsymptrOffLSym(s *obj.LSym, off int, x *obj.LSym, xoff int) int { + s.WriteOff(Ctxt, int64(off), x, int64(xoff)) + off += 4 + return off +} + func gdata(nam *Node, nr *Node, wid int) { if nam.Op != ONAME { Fatalf("gdata nam op %v", opnames[nam.Op]) diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index df9ef27b7a..ea67634260 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -879,7 +879,7 @@ func tracksym(t *Type, f *Field) *Sym { return Pkglookup(Tconv(t, FmtLeft)+"."+f.Sym.Name, trackpkg) } -func typelinksym(t *Type) *Sym { +func typelinkLSym(t *Type) *obj.LSym { // %-uT is what the generated Type's string field says. // It uses (ambiguous) package names instead of import paths. // %-T is the complete, unambiguous type name. @@ -889,13 +889,8 @@ func typelinksym(t *Type) *Sym { // ensure the types appear sorted by their string field. The // names are a little long but they are discarded by the linker // and do not end up in the symbol table of the final binary. - p := Tconv(t, FmtLeft|FmtUnsigned) + "\t" + Tconv(t, FmtLeft) - - s := Pkglookup(p, typelinkpkg) - - //print("typelinksym: %s -> %+S\n", p, s); - - return s + name := "go.typelink." + Tconv(t, FmtLeft|FmtUnsigned) + "\t" + Tconv(t, FmtLeft) + return obj.Linklookup(Ctxt, name, 0) } func typesymprefix(prefix string, t *Type) *Sym { @@ -1298,9 +1293,9 @@ ok: if t.Sym == nil { switch t.Etype { case TPTR32, TPTR64, TARRAY, TCHAN, TFUNC, TMAP, TSTRUCT: - slink := typelinksym(t) - dsymptr(slink, 0, s, 0) - ggloblsym(slink, int32(Widthptr), int16(dupok|obj.RODATA)) + slink := typelinkLSym(t) + dsymptrOffLSym(slink, 0, Linksym(s), 0) + ggloblLSym(slink, 4, int16(dupok|obj.RODATA)) } } diff --git a/src/cmd/internal/obj/data.go b/src/cmd/internal/obj/data.go index 37ab70bb0e..546ff37269 100644 --- a/src/cmd/internal/obj/data.go +++ b/src/cmd/internal/obj/data.go @@ -111,17 +111,36 @@ func (s *LSym) WriteInt(ctxt *Link, off int64, siz int, i int64) { // rsym and roff specify the relocation for the address. func (s *LSym) WriteAddr(ctxt *Link, off int64, siz int, rsym *LSym, roff int64) { if siz != ctxt.Arch.PtrSize { - ctxt.Diag("WriteAddr: bad address size: %d", siz) + ctxt.Diag("WriteAddr: bad address size %d in %s", siz, s.Name) } s.prepwrite(ctxt, off, siz) r := Addrel(s) r.Off = int32(off) + if int64(r.Off) != off { + ctxt.Diag("WriteAddr: off overflow %d in %s", off, s.Name) + } r.Siz = uint8(siz) r.Sym = rsym r.Type = R_ADDR r.Add = roff } +// WriteOff writes a 4 byte offset to rsym+roff into s at offset off. +// After linking the 4 bytes stored at s+off will be +// rsym+roff-(start of section that s is in). +func (s *LSym) WriteOff(ctxt *Link, off int64, rsym *LSym, roff int64) { + s.prepwrite(ctxt, off, 4) + r := Addrel(s) + r.Off = int32(off) + if int64(r.Off) != off { + ctxt.Diag("WriteOff: off overflow %d in %s", off, s.Name) + } + r.Siz = 4 + r.Sym = rsym + r.Type = R_ADDROFF + r.Add = roff +} + // WriteString writes a string of size siz into s at offset off. func (s *LSym) WriteString(ctxt *Link, off int64, siz int, str string) { if siz < len(str) { diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 62175f9ed8..d44d4398b1 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -457,6 +457,9 @@ const ( // R_ADDRMIPS (only used on mips64) resolves to a 32-bit external address, // by loading the address into a register with two instructions (lui, ori). R_ADDRMIPS + // R_ADDROFF resolves to an offset from the beginning of the section holding + // the data being relocated to the referenced symbol. + R_ADDROFF R_SIZE R_CALL R_CALLARM diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index ae7c287f59..cf51b0a908 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -525,6 +525,9 @@ func relocsym(s *LSym) { } 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) { @@ -1599,6 +1602,10 @@ func dodata() { sect.Vaddr = 0 Linklookup(Ctxt, "runtime.rodata", 0).Sect = sect Linklookup(Ctxt, "runtime.erodata", 0).Sect = sect + if !UseRelro() { + Linklookup(Ctxt, "runtime.types", 0).Sect = sect + Linklookup(Ctxt, "runtime.etypes", 0).Sect = sect + } for ; s != nil && s.Type < obj.STYPERELRO; s = s.Next { datsize = aligndatsize(datsize, s) s.Sect = sect @@ -1631,6 +1638,8 @@ func dodata() { sect.Align = maxalign(s, obj.STYPELINK-1) datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = 0 + Linklookup(Ctxt, "runtime.types", 0).Sect = sect + Linklookup(Ctxt, "runtime.etypes", 0).Sect = sect 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 { @@ -1970,10 +1979,12 @@ 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 @@ -2007,6 +2018,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 { @@ -2014,6 +2030,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/symtab.go b/src/cmd/link/internal/ld/symtab.go index ae0b17c259..678ed38730 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -329,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) @@ -537,6 +539,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/reflect/export_test.go b/src/reflect/export_test.go index ddc64b46be..037c953718 100644 --- a/src/reflect/export_test.go +++ b/src/reflect/export_test.go @@ -46,9 +46,11 @@ func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, func TypeLinks() []string { var r []string - for _, m := range typelinks() { - for _, t := range m { - r = append(r, t.string) + sections, offset := typelinks() + for i, offs := range offset { + rodata := sections[i] + for _, off := range offs { + r = append(r, rtypeOff(rodata, off).string) } } return r diff --git a/src/reflect/type.go b/src/reflect/type.go index 8f13acf26e..7104fde60a 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1558,30 +1558,48 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool { } // typelinks is implemented in package runtime. -// It returns a slice of all the 'typelink' information in the binary, -// which is to say a slice of known types, sorted by string. +// It returns a slice of the sections in each module, +// and a slice of *rtype offsets in each module. +// +// The types in each module are sorted by string. That is, the first +// two linked types of the first module are: +// +// d0 := sections[0] +// t1 := (*rtype)(add(d0, offset[0][0])) +// t2 := (*rtype)(add(d0, offset[0][1])) +// +// and +// +// t1.string < t2.string +// // Note that strings are not unique identifiers for types: // there can be more than one with a given string. // Only types we might want to look up are included: // pointers, channels, maps, slices, and arrays. -func typelinks() [][]*rtype +func typelinks() (sections []unsafe.Pointer, offset [][]int32) + +func rtypeOff(section unsafe.Pointer, off int32) *rtype { + return (*rtype)(add(section, uintptr(off))) +} // typesByString returns the subslice of typelinks() whose elements have // the given string representation. // It may be empty (no known types with that string) or may have // multiple elements (multiple types with that string). func typesByString(s string) []*rtype { - typs := typelinks() + sections, offset := typelinks() var ret []*rtype - for _, typ := range typs { + for offsI, offs := range offset { + section := sections[offsI] + // We are looking for the first index i where the string becomes >= s. // This is a copy of sort.Search, with f(h) replaced by (*typ[h].string >= s). - i, j := 0, len(typ) + i, j := 0, len(offs) for i < j { h := i + (j-i)/2 // avoid overflow when computing h // i ≤ h < j - if !(typ[h].string >= s) { + if !(rtypeOff(section, offs[h]).string >= s) { i = h + 1 // preserves f(i-1) == false } else { j = h // preserves f(j) == true @@ -1592,17 +1610,12 @@ func typesByString(s string) []*rtype { // Having found the first, linear scan forward to find the last. // We could do a second binary search, but the caller is going // to do a linear scan anyway. - j = i - for j < len(typ) && typ[j].string == s { - j++ - } - - if j > i { - if ret == nil { - ret = typ[i:j:j] - } else { - ret = append(ret, typ[i:j]...) + for j := i; j < len(offs); j++ { + typ := rtypeOff(section, offs[j]) + if typ.string != s { + break } + ret = append(ret, typ) } } return ret diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go index 95bebac593..e1956569fd 100644 --- a/src/runtime/runtime1.go +++ b/src/runtime/runtime1.go @@ -477,10 +477,12 @@ func gomcache() *mcache { } //go:linkname reflect_typelinks reflect.typelinks -func reflect_typelinks() [][]*_type { - ret := [][]*_type{firstmoduledata.typelinks} +func reflect_typelinks() ([]unsafe.Pointer, [][]int32) { + sections := []unsafe.Pointer{unsafe.Pointer(firstmoduledata.types)} + ret := [][]int32{firstmoduledata.typelinks} for datap := firstmoduledata.next; datap != nil; datap = datap.next { + sections = append(sections, unsafe.Pointer(datap.types)) ret = append(ret, datap.typelinks) } - return ret + return sections, ret } diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 158bdcea0d..8c70f22c1f 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -127,8 +127,9 @@ type moduledata struct { bss, ebss uintptr noptrbss, enoptrbss uintptr end, gcdata, gcbss uintptr + types, etypes uintptr - typelinks []*_type + typelinks []int32 // offsets from types itablinks []*itab modulename string -- cgit v1.3-5-g9baa From b0cbe158da10aac1876680e825a902d58a9d1bac Mon Sep 17 00:00:00 2001 From: Shahar Kohanim Date: Mon, 11 Apr 2016 22:19:34 +0300 Subject: cmd/link: move function only lsym fields to pcln struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit name old secs new secs delta LinkCmdGo 0.53 ± 9% 0.53 ±10% -1.30% (p=0.022 n=100+99) name old MaxRSS new MaxRSS delta LinkCmdGo 151k ± 4% 142k ± 6% -5.92% (p=0.000 n=98+100) Change-Id: Ic30e63a948f8e626b3396f458a0163f7234810c1 Reviewed-on: https://go-review.googlesource.com/21920 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/cmd/link/internal/ld/deadcode.go | 7 +++++-- src/cmd/link/internal/ld/dwarf.go | 2 +- src/cmd/link/internal/ld/lib.go | 17 ++++++++++++++--- src/cmd/link/internal/ld/link.go | 6 +++--- src/cmd/link/internal/ld/objfile.go | 13 +++++++------ src/cmd/link/internal/ld/pcln.go | 6 +++++- 6 files changed, 35 insertions(+), 16 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index 8b2d0d447e..83e4cdc077 100644 --- a/src/cmd/link/internal/ld/deadcode.go +++ b/src/cmd/link/internal/ld/deadcode.go @@ -272,9 +272,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.Pcln != nil { + for _, a := range s.Pcln.Autom { + d.mark(a.Gotype, s) + } } + } if strings.HasPrefix(s.Name, "type.") && s.Name[5] != '.' { diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index a3a931f94c..82689988c5 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -1556,7 +1556,7 @@ func writelines(prev *LSym) *LSym { dt, da int offs int64 ) - for _, a := range s.Autom { + for _, a := range s.Pcln.Autom { switch a.Name { case obj.A_AUTO: dt = DW_ABRV_AUTO diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 1f2df8b9c5..db34e68404 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1747,7 +1747,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.Pcln != nil { + locals = s.Pcln.Locals + } + limit = int(obj.StackLimit+locals) + int(Ctxt.FixedFrameSize()) } // Walk through sp adjustments in function, consuming relocs. @@ -1978,10 +1982,17 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) { for s := Ctxt.Textp; s != nil; s = s.Next { put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), s.Gotype) + locals := int32(0) + if s.Pcln != nil { + locals = s.Pcln.Locals + } // NOTE(ality): acid can't produce a stack trace without .frame symbols - put(nil, ".frame", 'm', int64(s.Locals)+int64(SysArch.PtrSize), 0, 0, nil) + put(nil, ".frame", 'm', int64(locals)+int64(SysArch.PtrSize), 0, 0, nil) - for _, a := range s.Autom { + if s.Pcln == nil { + continue + } + for _, a := range s.Pcln.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 { diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index 52b52f1cc0..93454fb4b2 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -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,7 +65,6 @@ type LSym struct { Dynimplib string Dynimpvers string Sect *Section - Autom []Auto Pcln *Pcln P []byte R []Reloc @@ -221,6 +218,9 @@ type Library struct { } type Pcln struct { + Args int32 + Locals int32 + Autom []Auto Pcsp Pcdata Pcfile Pcdata Pcline Pcdata diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go index 578afd4c74..eacccb59fb 100644 --- a/src/cmd/link/internal/ld/objfile.go +++ b/src/cmd/link/internal/ld/objfile.go @@ -331,8 +331,11 @@ overwrite: } if s.Type == obj.STEXT { - s.Args = r.readInt32() - s.Locals = r.readInt32() + s.Pcln = new(Pcln) + pc := s.Pcln + + pc.Args = r.readInt32() + pc.Locals = r.readInt32() if r.readUint8() != 0 { s.Attr |= AttrNoSplit } @@ -341,13 +344,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(), @@ -355,8 +358,6 @@ overwrite: } } - s.Pcln = new(Pcln) - pc := s.Pcln pc.Pcsp.P = r.readData() pc.Pcfile.P = r.readData() pc.Pcline.P = r.readData() diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index 9a947c7c07..3ef52444af 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -293,7 +293,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.Pcln != nil { + args = uint32(Ctxt.Cursym.Pcln.Args) + } + off = int32(setuint32(Ctxt, ftab, int64(off), args)) // frame int32 // This has been removed (it was never set quite correctly anyway). -- cgit v1.3-5-g9baa From 61b7a9c57bb6b9c259360239001b2d5be4876abd Mon Sep 17 00:00:00 2001 From: Shahar Kohanim Date: Tue, 12 Apr 2016 23:18:47 +0300 Subject: cmd/link: rename Pcln to FuncInfo After non pcln fields were added to it in a previous commit. Change-Id: Icf92c0774d157c61399a6fc2a3c4d2cd47a634d2 Reviewed-on: https://go-review.googlesource.com/21921 Run-TryBot: Shahar Kohanim TryBot-Result: Gobot Gobot Reviewed-by: David Crawshaw --- src/cmd/link/internal/ld/deadcode.go | 10 +++++----- src/cmd/link/internal/ld/dwarf.go | 16 ++++++++-------- src/cmd/link/internal/ld/lib.go | 16 ++++++++-------- src/cmd/link/internal/ld/link.go | 4 ++-- src/cmd/link/internal/ld/objfile.go | 4 ++-- src/cmd/link/internal/ld/pcln.go | 10 +++++----- 6 files changed, 30 insertions(+), 30 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index 83e4cdc077..51fae02ef0 100644 --- a/src/cmd/link/internal/ld/deadcode.go +++ b/src/cmd/link/internal/ld/deadcode.go @@ -272,8 +272,8 @@ func (d *deadcodepass) flood() { if Debug['v'] > 1 { fmt.Fprintf(d.ctxt.Bso, "marktext %s\n", s.Name) } - if s.Pcln != nil { - for _, a := range s.Pcln.Autom { + if s.FuncInfo != nil { + for _, a := range s.FuncInfo.Autom { d.mark(a.Gotype, s) } } @@ -335,9 +335,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/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 82689988c5..b1208b63a8 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -1345,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 @@ -1514,14 +1514,14 @@ func writelines(prev *LSym) *LSym { 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) { @@ -1556,7 +1556,7 @@ func writelines(prev *LSym) *LSym { dt, da int offs int64 ) - for _, a := range s.Pcln.Autom { + for _, a := range s.FuncInfo.Autom { switch a.Name { case obj.A_AUTO: dt = DW_ABRV_AUTO @@ -1698,14 +1698,14 @@ func writeframes(prev *LSym) *LSym { var pcsp Pciter for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next { 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, diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index db34e68404..bdcc84a129 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1710,7 +1710,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. @@ -1748,8 +1748,8 @@ func stkcheck(up *Chain, depth int) int { } // Raise limit to allow frame. locals := int32(0) - if s.Pcln != nil { - locals = s.Pcln.Locals + if s.FuncInfo != nil { + locals = s.FuncInfo.Locals } limit = int(obj.StackLimit+locals) + int(Ctxt.FixedFrameSize()) } @@ -1761,7 +1761,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. @@ -1983,16 +1983,16 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) { put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), s.Gotype) locals := int32(0) - if s.Pcln != nil { - locals = s.Pcln.Locals + 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(locals)+int64(SysArch.PtrSize), 0, 0, nil) - if s.Pcln == nil { + if s.FuncInfo == nil { continue } - for _, a := range s.Pcln.Autom { + 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 { diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index 93454fb4b2..b0bca4300f 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -65,7 +65,7 @@ type LSym struct { Dynimplib string Dynimpvers string Sect *Section - Pcln *Pcln + FuncInfo *FuncInfo P []byte R []Reloc } @@ -217,7 +217,7 @@ type Library struct { hash []byte } -type Pcln struct { +type FuncInfo struct { Args int32 Locals int32 Autom []Auto diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go index eacccb59fb..6826737cae 100644 --- a/src/cmd/link/internal/ld/objfile.go +++ b/src/cmd/link/internal/ld/objfile.go @@ -331,8 +331,8 @@ overwrite: } if s.Type == obj.STEXT { - s.Pcln = new(Pcln) - pc := s.Pcln + s.FuncInfo = new(FuncInfo) + pc := s.FuncInfo pc.Args = r.readInt32() pc.Locals = r.readInt32() diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index 3ef52444af..74ef8c2929 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -204,7 +204,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 @@ -255,13 +255,13 @@ func pclntab() { var i int32 var it Pciter var off int32 - var pcln *Pcln + var pcln *FuncInfo for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next { last = Ctxt.Cursym if container(Ctxt.Cursym) != 0 { continue } - pcln = Ctxt.Cursym.Pcln + pcln = Ctxt.Cursym.FuncInfo if pcln == nil { pcln = &pclntab_zpcln } @@ -294,8 +294,8 @@ func pclntab() { // args int32 // TODO: Move into funcinfo. args := uint32(0) - if Ctxt.Cursym.Pcln != nil { - args = uint32(Ctxt.Cursym.Pcln.Args) + if Ctxt.Cursym.FuncInfo != nil { + args = uint32(Ctxt.Cursym.FuncInfo.Args) } off = int32(setuint32(Ctxt, ftab, int64(off), args)) -- cgit v1.3-5-g9baa From 7d469179e6e3dafe16700b7fc1cf8683ad9453fa Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Mon, 28 Mar 2016 10:32:27 -0400 Subject: cmd/compile, etc: store method tables as offsets This CL introduces the typeOff type and a lookup method of the same name that can turn a typeOff offset into an *rtype. In a typical Go binary (built with buildmode=exe, pie, c-archive, or c-shared), there is one moduledata and all typeOff values are offsets relative to firstmoduledata.types. This makes computing the pointer cheap in typical programs. With buildmode=shared (and one day, buildmode=plugin) there are multiple modules whose relative offset is determined at runtime. We identify a type in the general case by the pair of the original *rtype that references it and its typeOff value. We determine the module from the original pointer, and then use the typeOff from there to compute the final *rtype. To ensure there is only one *rtype representing each type, the runtime initializes a typemap for each module, using any identical type from an earlier module when resolving that offset. This means that types computed from an offset match the type mapped by the pointer dynamic relocations. A series of followup CLs will replace other *rtype values with typeOff (and name/*string with nameOff). For types created at runtime by reflect, type offsets are treated as global IDs and reference into a reflect offset map kept by the runtime. darwin/amd64: cmd/go: -57KB (0.6%) jujud: -557KB (0.8%) linux/amd64 PIE: cmd/go: -361KB (3.0%) jujud: -3.5MB (4.2%) For #6853. Change-Id: Icf096fd884a0a0cb9f280f46f7a26c70a9006c96 Reviewed-on: https://go-review.googlesource.com/21285 Reviewed-by: Ian Lance Taylor Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/reflect.go | 75 +++++--- src/cmd/internal/obj/link.go | 15 +- src/cmd/link/internal/ld/deadcode.go | 14 +- src/cmd/link/internal/ld/decodesym.go | 22 +-- src/reflect/export_test.go | 2 +- src/reflect/type.go | 267 +++++++++++++++++++++------- src/reflect/value.go | 15 +- src/runtime/iface.go | 10 +- src/runtime/proc.go | 3 +- src/runtime/runtime1.go | 33 ++++ src/runtime/symtab.go | 2 + src/runtime/type.go | 307 ++++++++++++++++++++++++++++++++- 12 files changed, 637 insertions(+), 128 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index ea67634260..2bd50b4665 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -75,7 +75,7 @@ func uncommonSize(t *Type) int { // Sizeof(runtime.uncommontype{}) if t.Sym == nil && len(methods(t)) == 0 { return 0 } - return 2*Widthptr + 2*Widthint + return 2 * Widthptr } func makefield(name string, t *Type) *Field { @@ -580,13 +580,23 @@ func dextratype(s *Sym, ot int, t *Type, dataAdd int) int { ot = dgopkgpath(s, ot, typePkg(t)) - // slice header - ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint+dataAdd) - - n := len(m) - ot = duintxx(s, ot, uint64(n), Widthint) - ot = duintxx(s, ot, uint64(n), Widthint) + dataAdd += Widthptr + 2 + 2 + if Widthptr == 8 { + dataAdd += 4 + } + mcount := len(m) + if mcount != int(uint16(mcount)) { + Fatalf("too many methods on %s: %d", t, mcount) + } + if dataAdd != int(uint16(dataAdd)) { + Fatalf("methods are too far away on %s: %d", t, dataAdd) + } + ot = duint16(s, ot, uint16(mcount)) + ot = duint16(s, ot, uint16(dataAdd)) + if Widthptr == 8 { + ot = duint32(s, ot, 0) // align for following pointers + } return ot } @@ -609,6 +619,7 @@ func typePkg(t *Type) *Pkg { // dextratypeData dumps the backing array for the []method field of // runtime.uncommontype. func dextratypeData(s *Sym, ot int, t *Type) int { + lsym := Linksym(s) for _, a := range methods(t) { // ../../../../runtime/type.go:/method exported := exportname(a.name) @@ -617,21 +628,24 @@ func dextratypeData(s *Sym, ot int, t *Type) int { pkg = a.pkg } ot = dname(s, ot, a.name, "", pkg, exported) - ot = dmethodptr(s, ot, dtypesym(a.mtype)) - ot = dmethodptr(s, ot, a.isym) - ot = dmethodptr(s, ot, a.tsym) + ot = dmethodptrOffLSym(lsym, ot, Linksym(dtypesym(a.mtype))) + ot = dmethodptrOffLSym(lsym, ot, Linksym(a.isym)) + ot = dmethodptrOffLSym(lsym, ot, Linksym(a.tsym)) + if Widthptr == 8 { + ot = duintxxLSym(lsym, ot, 0, 4) // pad to reflect.method size + } } return ot } -func dmethodptr(s *Sym, off int, x *Sym) int { - duintptr(s, off, 0) - r := obj.Addrel(Linksym(s)) - r.Off = int32(off) - r.Siz = uint8(Widthptr) - r.Sym = Linksym(x) - r.Type = obj.R_METHOD - return off + Widthptr +func dmethodptrOffLSym(s *obj.LSym, ot int, x *obj.LSym) int { + duintxxLSym(s, ot, 0, 4) + r := obj.Addrel(s) + r.Off = int32(ot) + r.Siz = 4 + r.Sym = x + r.Type = obj.R_METHODOFF + return ot + 4 } var kinds = []int{ @@ -1286,18 +1300,29 @@ ok: ggloblsym(s, int32(ot), int16(dupok|obj.RODATA)) // generate typelink.foo pointing at s = type.foo. + // // The linker will leave a table of all the typelinks for - // types in the binary, so reflect can find them. - // We only need the link for unnamed composites that - // we want be able to find. - if t.Sym == nil { + // types in the binary, so the runtime can find them. + // + // When buildmode=shared, all types are in typelinks so the + // runtime can deduplicate type pointers. + keep := Ctxt.Flag_dynlink + if !keep && t.Sym == nil { + // For an unnamed type, we only need the link if the type can + // be created at run time by reflect.PtrTo and similar + // functions. If the type exists in the program, those + // functions must return the existing type structure rather + // than creating a new one. switch t.Etype { case TPTR32, TPTR64, TARRAY, TCHAN, TFUNC, TMAP, TSTRUCT: - slink := typelinkLSym(t) - dsymptrOffLSym(slink, 0, Linksym(s), 0) - ggloblLSym(slink, 4, int16(dupok|obj.RODATA)) + keep = true } } + if keep { + slink := typelinkLSym(t) + dsymptrOffLSym(slink, 0, Linksym(s), 0) + ggloblLSym(slink, 4, int16(dupok|obj.RODATA)) + } return s } diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index 42aaa5f4f0..55c9f4f9e2 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -457,8 +457,8 @@ const ( // R_ADDRMIPS (only used on mips64) resolves to a 32-bit external address, // by loading the address into a register with two instructions (lui, ori). R_ADDRMIPS - // R_ADDROFF resolves to an offset from the beginning of the section holding - // the data being relocated to the referenced symbol. + // R_ADDROFF resolves to a 32-bit offset from the beginning of the section + // holding the data being relocated to the referenced symbol. R_ADDROFF R_SIZE R_CALL @@ -492,11 +492,12 @@ const ( // should be linked into the final binary, even if there are no other // direct references. (This is used for types reachable by reflection.) R_USETYPE - // R_METHOD resolves to an *rtype for a method. - // It is used when linking from the uncommonType of another *rtype, and - // may be set to zero by the linker if it determines the method text is - // unreachable by the linked program. - R_METHOD + // R_METHODOFF resolves to a 32-bit offset from the beginning of the section + // holding the data being relocated to the referenced symbol. + // It is a variant of R_ADDROFF used when linking from the uncommonType of a + // *rtype, and may be set to zero by the linker if it determines the method + // text is unreachable by the linked program. + R_METHODOFF R_POWER_TOC R_GOTPCREL // R_JMPMIPS (only used on mips64) resolves to non-PC-relative target address diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index 51fae02ef0..c83a104a54 100644 --- a/src/cmd/link/internal/ld/deadcode.go +++ b/src/cmd/link/internal/ld/deadcode.go @@ -19,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: @@ -100,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) @@ -167,7 +167,7 @@ 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) ifn() *LSym { return m.r[1].Sym } @@ -190,7 +190,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) @@ -217,7 +217,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 } } @@ -291,14 +291,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 } diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index 7daa8bc812..5fa8b4c81f 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -47,9 +47,9 @@ func decode_inuxi(p []byte, sz int) uint64 { } } -func commonsize() int { return 6*SysArch.PtrSize + 8 } // runtime._type -func structfieldSize() int { return 3 * SysArch.PtrSize } // runtime.structfield -func uncommonSize() int { return 2*SysArch.PtrSize + 2*SysArch.IntSize } // runtime.uncommontype +func commonsize() int { return 6*SysArch.PtrSize + 8 } // runtime._type +func structfieldSize() int { return 3 * SysArch.PtrSize } // runtime.structfield +func uncommonSize() int { return 2 * SysArch.PtrSize } // runtime.uncommontype // Type.commonType.kind func decodetype_kind(s *LSym) uint8 { @@ -341,12 +341,14 @@ func decodetype_methods(s *LSym) []methodsig { // just Sizeof(rtype) } - numMethods := int(decode_inuxi(s.P[off+2*SysArch.PtrSize:], SysArch.IntSize)) - r := decode_reloc(s, int32(off+SysArch.PtrSize)) - if r.Sym != s { - panic(fmt.Sprintf("method slice pointer in %s leads to a different symbol %s", s, r.Sym)) + mcount := int(decode_inuxi(s.P[off+SysArch.PtrSize:], 2)) + moff := int(decode_inuxi(s.P[off+SysArch.PtrSize+2:], 2)) + off += moff // offset to array of reflect.method values + var sizeofMethod int // sizeof reflect.method in program + if SysArch.PtrSize == 4 { + sizeofMethod = 4 * SysArch.PtrSize + } else { + sizeofMethod = 3 * SysArch.PtrSize } - off = int(r.Add) // array of reflect.method values - sizeofMethod := 4 * SysArch.PtrSize // sizeof reflect.method in program - return decode_methodsig(s, off, sizeofMethod, numMethods) + return decode_methodsig(s, off, sizeofMethod, mcount) } diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go index 037c953718..2769e0db40 100644 --- a/src/reflect/export_test.go +++ b/src/reflect/export_test.go @@ -90,7 +90,7 @@ func FirstMethodNameBytes(t Type) *byte { if ut == nil { panic("type has no methods") } - m := ut.methods[0] + m := ut.methods()[0] if *m.name.data(0)&(1<<2) == 0 { panic("method name does not have pkgPath *string") } diff --git a/src/reflect/type.go b/src/reflect/type.go index 7104fde60a..c7ed402be2 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -288,10 +288,10 @@ type typeAlg struct { // Method on non-interface type type method struct { - name name // name of method - mtyp *rtype // method type (without receiver) - ifn unsafe.Pointer // fn used in interface call (one-word receiver) - tfn unsafe.Pointer // fn used for normal method call + name name // name of method + mtyp typeOff // method type (without receiver) + ifn textOff // fn used in interface call (one-word receiver) + tfn textOff // fn used for normal method call } // uncommonType is present only for types with names or methods @@ -299,8 +299,9 @@ type method struct { // Using a pointer to this struct reduces the overall size required // to describe an unnamed type with no methods. type uncommonType struct { - pkgPath *string // import path; nil for built-in types like int, string - methods []method // methods associated with type + pkgPath *string // import path; nil for built-in types like int, string + mcount uint16 // number of methods + moff uint16 // offset from this uncommontype to [mcount]method } // ChanDir represents a channel type's direction. @@ -589,6 +590,10 @@ var kindNames = []string{ UnsafePointer: "unsafe.Pointer", } +func (t *uncommonType) methods() []method { + return (*[1 << 16]method)(add(unsafe.Pointer(t), uintptr(t.moff)))[:t.mcount:t.mcount] +} + func (t *uncommonType) PkgPath() string { if t == nil || t.pkgPath == nil { return "" @@ -596,13 +601,55 @@ func (t *uncommonType) PkgPath() string { return *t.pkgPath } +// resolveTypeOff resolves an *rtype offset from a base type. +// The (*rtype).typeOff method is a convenience wrapper for this function. +// Implemented in the runtime package. +func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer + +// resolveTextOff resolves an function pointer offset from a base type. +// The (*rtype).textOff method is a convenience wrapper for this function. +// Implemented in the runtime package. +func resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer + +// addReflectOff adds a pointer to the reflection lookup map in the runtime. +// It returns a new ID that can be used as a typeOff or textOff, and will +// be resolved correctly. Implemented in the runtime package. +func addReflectOff(ptr unsafe.Pointer) int32 + +// resolveReflectType adds a *rtype to the reflection lookup map in the runtime. +// It returns a new typeOff that can be used to refer to the pointer. +func resolveReflectType(t *rtype) typeOff { + return typeOff(addReflectOff(unsafe.Pointer(t))) +} + +// resolveReflectText adds a function pointer to the reflection lookup map in +// the runtime. It returns a new textOff that can be used to refer to the +// pointer. +func resolveReflectText(ptr unsafe.Pointer) textOff { + return textOff(addReflectOff(ptr)) +} + +type typeOff int32 // offset to an *rtype +type textOff int32 // offset from top of text section + +func (t *rtype) typeOff(off typeOff) *rtype { + if off == 0 { + return nil + } + return (*rtype)(resolveTypeOff(unsafe.Pointer(t), int32(off))) +} + +func (t *rtype) textOff(off textOff) unsafe.Pointer { + return resolveTextOff(unsafe.Pointer(t), int32(off)) +} + func (t *rtype) uncommon() *uncommonType { if t.tflag&tflagUncommon == 0 { return nil } switch t.Kind() { case Struct: - return &(*structTypeWithMethods)(unsafe.Pointer(t)).u + return &(*structTypeUncommon)(unsafe.Pointer(t)).u case Ptr: type u struct { ptrType @@ -688,7 +735,7 @@ func (t *rtype) NumMethod() int { if ut == nil { return 0 } - return len(ut.methods) + return int(ut.mcount) } func (t *rtype) Method(i int) (m Method) { @@ -698,10 +745,10 @@ func (t *rtype) Method(i int) (m Method) { } ut := t.uncommon() - if ut == nil || i < 0 || i >= len(ut.methods) { + if ut == nil || i < 0 || i >= int(ut.mcount) { panic("reflect: Method index out of range") } - p := &ut.methods[i] + p := ut.methods()[i] m.Name = p.name.name() fl := flag(Func) if !p.name.isExported() { @@ -712,8 +759,9 @@ func (t *rtype) Method(i int) (m Method) { m.PkgPath = *pkgPath fl |= flagStickyRO } - if p.mtyp != nil { - ft := (*funcType)(unsafe.Pointer(p.mtyp)) + if p.mtyp != 0 { + mtyp := t.typeOff(p.mtyp) + ft := (*funcType)(unsafe.Pointer(mtyp)) in := make([]Type, 0, 1+len(ft.in())) in = append(in, t) for _, arg := range ft.in() { @@ -723,9 +771,10 @@ func (t *rtype) Method(i int) (m Method) { for _, ret := range ft.out() { out = append(out, ret) } - mt := FuncOf(in, out, p.mtyp.IsVariadic()) + mt := FuncOf(in, out, ft.IsVariadic()) m.Type = mt - fn := unsafe.Pointer(&p.tfn) + tfn := t.textOff(p.tfn) + fn := unsafe.Pointer(&tfn) m.Func = Value{mt.(*rtype), fn, fl} } m.Index = i @@ -741,8 +790,9 @@ func (t *rtype) MethodByName(name string) (m Method, ok bool) { if ut == nil { return Method{}, false } - for i := range ut.methods { - p := &ut.methods[i] + utmethods := ut.methods() + for i := 0; i < int(ut.mcount); i++ { + p := utmethods[i] if p.name.name() == name { return t.Method(i), true } @@ -1430,10 +1480,11 @@ func implements(T, V *rtype) bool { return false } i := 0 - for j := 0; j < len(v.methods); j++ { + vmethods := v.methods() + for j := 0; j < int(v.mcount); j++ { tm := &t.methods[i] - vm := &v.methods[j] - if vm.name.name() == tm.name.name() && vm.mtyp == tm.typ { + vm := vmethods[j] + if vm.name.name() == tm.name.name() && V.typeOff(vm.mtyp) == tm.typ { if i++; i >= len(t.methods) { return true } @@ -2161,21 +2212,55 @@ func SliceOf(t Type) Type { return cachePut(ckey, &slice.rtype) } -// structTypeWithMethods is a structType created at runtime with StructOf. -// It is needed to pin the []method slice from its associated uncommonType struct. -// Keep in sync with the memory layout of structType. -type structTypeWithMethods struct { - structType - u uncommonType -} - // The structLookupCache caches StructOf lookups. // StructOf does not share the common lookupCache since we need to pin -// the *structType and its associated *uncommonType (especially the -// []method slice field of that uncommonType.) +// the memory associated with *structTypeFixedN. var structLookupCache struct { sync.RWMutex - m map[uint32][]*structTypeWithMethods // keyed by hash calculated in StructOf + m map[uint32][]interface { + common() *rtype + } // keyed by hash calculated in StructOf +} + +type structTypeUncommon struct { + structType + u uncommonType +} + +// A *rtype representing a struct is followed directly in memory by an +// array of method objects representing the methods attached to the +// struct. To get the same layout for a run time generated type, we +// need an array directly following the uncommonType memory. The types +// structTypeFixed4, ...structTypeFixedN are used to do this. +// +// A similar strategy is used for funcTypeFixed4, ...funcTypeFixedN. + +// TODO(crawshaw): as these structTypeFixedN and funcTypeFixedN structs +// have no methods, they could be defined at runtime using the StructOf +// function. + +type structTypeFixed4 struct { + structType + u uncommonType + m [4]method +} + +type structTypeFixed8 struct { + structType + u uncommonType + m [8]method +} + +type structTypeFixed16 struct { + structType + u uncommonType + m [16]method +} + +type structTypeFixed32 struct { + structType + u uncommonType + m [32]method } // StructOf returns the struct type containing fields. @@ -2192,7 +2277,7 @@ func StructOf(fields []StructField) Type { typalign uint8 comparable = true hashable = true - typ = new(structTypeWithMethods) + methods []method fs = make([]structField, len(fields)) repr = make([]byte, 0, 64) @@ -2269,7 +2354,6 @@ func StructOf(fields []StructField) Type { } return recv.Field(ifield).Method(imethod).Call(args) }) - } else { tfn = MakeFunc(m.typ, func(in []Value) []Value { var args []Value @@ -2287,47 +2371,59 @@ func StructOf(fields []StructField) Type { } return recv.Field(ifield).Method(imethod).Call(args) }) - } - typ.u.methods = append( - typ.u.methods, - method{ - name: m.name, - mtyp: m.typ, - ifn: unsafe.Pointer(&ifn), - tfn: unsafe.Pointer(&tfn), - }, - ) + methods = append(methods, method{ + name: m.name, + mtyp: resolveReflectType(m.typ), + ifn: resolveReflectText(unsafe.Pointer(&ifn)), + tfn: resolveReflectText(unsafe.Pointer(&tfn)), + }) } case Ptr: ptr := (*ptrType)(unsafe.Pointer(ft)) if unt := ptr.uncommon(); unt != nil { - for _, m := range unt.methods { + for _, m := range unt.methods() { if m.name.pkgPath() != nil { // TODO(sbinet) panic("reflect: embedded interface with unexported method(s) not implemented") } - typ.u.methods = append(typ.u.methods, m) + methods = append(methods, method{ + name: m.name, + mtyp: resolveReflectType(ptr.typeOff(m.mtyp)), + ifn: resolveReflectText(ptr.textOff(m.ifn)), + tfn: resolveReflectText(ptr.textOff(m.tfn)), + }) } } if unt := ptr.elem.uncommon(); unt != nil { - for _, m := range unt.methods { + for _, m := range unt.methods() { if m.name.pkgPath() != nil { // TODO(sbinet) panic("reflect: embedded interface with unexported method(s) not implemented") } - typ.u.methods = append(typ.u.methods, m) + methods = append(methods, method{ + name: m.name, + mtyp: resolveReflectType(ptr.elem.typeOff(m.mtyp)), + ifn: resolveReflectText(ptr.elem.textOff(m.ifn)), + tfn: resolveReflectText(ptr.elem.textOff(m.tfn)), + }) } } default: if unt := ft.uncommon(); unt != nil { - for _, m := range unt.methods { + for _, m := range unt.methods() { if m.name.pkgPath() != nil { // TODO(sbinet) panic("reflect: embedded interface with unexported method(s) not implemented") } - typ.u.methods = append(typ.u.methods, m) + methods = append(methods, method{ + name: m.name, + mtyp: resolveReflectType(ft.typeOff(m.mtyp)), + ifn: resolveReflectText(ft.textOff(m.ifn)), + tfn: resolveReflectText(ft.textOff(m.tfn)), + }) + } } } @@ -2359,6 +2455,49 @@ func StructOf(fields []StructField) Type { fs[i] = f } + + var typ *structType + var ut *uncommonType + var typPin interface { + common() *rtype + } // structTypeFixedN + + switch { + case len(methods) == 0: + t := new(structTypeUncommon) + typ = &t.structType + ut = &t.u + typPin = t + case len(methods) <= 4: + t := new(structTypeFixed4) + typ = &t.structType + ut = &t.u + copy(t.m[:], methods) + typPin = t + case len(methods) <= 8: + t := new(structTypeFixed8) + typ = &t.structType + ut = &t.u + copy(t.m[:], methods) + typPin = t + case len(methods) <= 16: + t := new(structTypeFixed16) + typ = &t.structType + ut = &t.u + copy(t.m[:], methods) + typPin = t + case len(methods) <= 32: + t := new(structTypeFixed32) + typ = &t.structType + ut = &t.u + copy(t.m[:], methods) + typPin = t + default: + panic("reflect.StructOf: too many methods") + } + ut.mcount = uint16(len(methods)) + ut.moff = uint16(unsafe.Sizeof(uncommonType{})) + if len(fs) > 0 { repr = append(repr, ' ') } @@ -2372,15 +2511,16 @@ func StructOf(fields []StructField) Type { // Make the struct type. var istruct interface{} = struct{}{} prototype := *(**structType)(unsafe.Pointer(&istruct)) - typ.structType = *prototype - typ.structType.fields = fs + *typ = *prototype + typ.fields = fs // Look in cache structLookupCache.RLock() - for _, t := range structLookupCache.m[hash] { - if haveIdenticalUnderlyingType(&typ.rtype, &t.rtype) { + for _, st := range structLookupCache.m[hash] { + t := st.common() + if haveIdenticalUnderlyingType(&typ.rtype, t) { structLookupCache.RUnlock() - return &t.rtype + return t } } structLookupCache.RUnlock() @@ -2389,11 +2529,14 @@ func StructOf(fields []StructField) Type { structLookupCache.Lock() defer structLookupCache.Unlock() if structLookupCache.m == nil { - structLookupCache.m = make(map[uint32][]*structTypeWithMethods) + structLookupCache.m = make(map[uint32][]interface { + common() *rtype + }) } - for _, t := range structLookupCache.m[hash] { - if haveIdenticalUnderlyingType(&typ.rtype, &t.rtype) { - return &t.rtype + for _, st := range structLookupCache.m[hash] { + t := st.common() + if haveIdenticalUnderlyingType(&typ.rtype, t) { + return t } } @@ -2403,9 +2546,8 @@ func StructOf(fields []StructField) Type { // even if 't' wasn't a structType with methods, we should be ok // as the 'u uncommonType' field won't be accessed except when // tflag&tflagUncommon is set. - tt := (*structTypeWithMethods)(unsafe.Pointer(t)) - structLookupCache.m[hash] = append(structLookupCache.m[hash], tt) - return &tt.rtype + structLookupCache.m[hash] = append(structLookupCache.m[hash], t) + return t } } @@ -2414,7 +2556,7 @@ func StructOf(fields []StructField) Type { typ.size = size typ.align = typalign typ.fieldAlign = typalign - if len(typ.u.methods) > 0 { + if len(methods) > 0 { typ.tflag |= tflagUncommon } if !hasPtr { @@ -2514,7 +2656,7 @@ func StructOf(fields []StructField) Type { typ.kind &^= kindDirectIface } - structLookupCache.m[hash] = append(structLookupCache.m[hash], typ) + structLookupCache.m[hash] = append(structLookupCache.m[hash], typPin) return &typ.rtype } @@ -2533,6 +2675,7 @@ func runtimeStructField(field StructField) structField { } } + _ = resolveReflectType(field.Type.common()) return structField{ name: newName(field.Name, string(field.Tag), field.PkgPath, exported), typ: field.Type.common(), diff --git a/src/reflect/value.go b/src/reflect/value.go index 262545d973..d72c14e9e1 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -566,15 +566,16 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn } else { rcvrtype = v.typ ut := v.typ.uncommon() - if ut == nil || uint(i) >= uint(len(ut.methods)) { + if ut == nil || uint(i) >= uint(ut.mcount) { panic("reflect: internal error: invalid method index") } - m := &ut.methods[i] + m := ut.methods()[i] if !m.name.isExported() { panic("reflect: " + op + " of unexported method") } - fn = unsafe.Pointer(&m.ifn) - t = m.mtyp + ifn := v.typ.textOff(m.ifn) + fn = unsafe.Pointer(&ifn) + t = v.typ.typeOff(m.mtyp) } return } @@ -1687,11 +1688,11 @@ func (v Value) Type() Type { } // Method on concrete type. ut := v.typ.uncommon() - if ut == nil || uint(i) >= uint(len(ut.methods)) { + if ut == nil || uint(i) >= uint(ut.mcount) { panic("reflect: internal error: invalid method index") } - m := &ut.methods[i] - return m.mtyp + m := ut.methods()[i] + return v.typ.typeOff(m.mtyp) } // Uint returns v's underlying value, as a uint64. diff --git a/src/runtime/iface.go b/src/runtime/iface.go index a4c962fb7a..700bdc2f48 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -93,7 +93,8 @@ func additab(m *itab, locked, canfail bool) { // so can iterate over both in lock step; // the loop is O(ni+nt) not O(ni*nt). ni := len(inter.mhdr) - nt := len(x.mhdr) + nt := int(x.mcount) + xmhdr := (*[1 << 16]method)(add(unsafe.Pointer(x), uintptr(x.moff)))[:nt:nt] j := 0 for k := 0; k < ni; k++ { i := &inter.mhdr[k] @@ -104,15 +105,16 @@ func additab(m *itab, locked, canfail bool) { ipkg = inter.pkgpath } for ; j < nt; j++ { - t := &x.mhdr[j] - if t.mtyp == itype && t.name.name() == iname { + t := &xmhdr[j] + if typ.typeOff(t.mtyp) == itype && t.name.name() == iname { pkgPath := t.name.pkgPath() if pkgPath == nil { pkgPath = x.pkgpath } if t.name.isExported() || pkgPath == ipkg { if m != nil { - *(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = t.ifn + ifn := typ.textOff(t.ifn) + *(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = ifn } goto nextimethod } diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 1a9dbd6c53..98a986cd63 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -435,9 +435,10 @@ func schedinit() { tracebackinit() moduledataverify() stackinit() - itabsinit() mallocinit() mcommoninit(_g_.m) + typelinksinit() + itabsinit() msigsave(_g_.m) initSigmask = _g_.m.sigmask diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go index e1956569fd..02aeedaf75 100644 --- a/src/runtime/runtime1.go +++ b/src/runtime/runtime1.go @@ -486,3 +486,36 @@ func reflect_typelinks() ([]unsafe.Pointer, [][]int32) { } return sections, ret } + +// reflect_resolveTypeOff resolves an *rtype offset from a base type. +//go:linkname reflect_resolveTypeOff reflect.resolveTypeOff +func reflect_resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer { + return unsafe.Pointer((*_type)(rtype).typeOff(typeOff(off))) +} + +// reflect_resolveTextOff resolves an function pointer offset from a base type. +//go:linkname reflect_resolveTextOff reflect.resolveTextOff +func reflect_resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer { + return (*_type)(rtype).textOff(textOff(off)) + +} + +// reflect_addReflectOff adds a pointer to the reflection offset lookup map. +//go:linkname reflect_addReflectOff reflect.addReflectOff +func reflect_addReflectOff(ptr unsafe.Pointer) int32 { + lock(&reflectOffs.lock) + if reflectOffs.m == nil { + reflectOffs.m = make(map[int32]unsafe.Pointer) + reflectOffs.minv = make(map[unsafe.Pointer]int32) + reflectOffs.next = -1 + } + id, found := reflectOffs.minv[ptr] + if !found { + id = reflectOffs.next + reflectOffs.next-- // use negative offsets as IDs to aid debugging + reflectOffs.m[id] = ptr + reflectOffs.minv[ptr] = id + } + unlock(&reflectOffs.lock) + return id +} diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 8c70f22c1f..2df390253a 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -137,6 +137,8 @@ type moduledata struct { gcdatamask, gcbssmask bitvector + typemap map[typeOff]*_type // offset to *_rtype in previous module + next *moduledata } diff --git a/src/runtime/type.go b/src/runtime/type.go index fbf6f9973c..86131d3ff3 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -131,6 +131,92 @@ func (t *_type) name() string { return t._string[i+1:] } +// reflectOffs holds type offsets defined at run time by the reflect package. +// +// When a type is defined at run time, its *rtype data lives on the heap. +// There are a wide range of possible addresses the heap may use, that +// may not be representable as a 32-bit offset. Moreover the GC may +// one day start moving heap memory, in which case there is no stable +// offset that can be defined. +// +// To provide stable offsets, we add pin *rtype objects in a global map +// and treat the offset as an identifier. We use negative offsets that +// do not overlap with any compile-time module offsets. +// +// Entries are created by reflect.addReflectOff. +var reflectOffs struct { + lock mutex + next int32 + m map[int32]unsafe.Pointer + minv map[unsafe.Pointer]int32 +} + +func (t *_type) typeOff(off typeOff) *_type { + if off == 0 { + return nil + } + base := uintptr(unsafe.Pointer(t)) + var md *moduledata + for next := &firstmoduledata; next != nil; next = next.next { + if base >= next.types && base < next.etypes { + md = next + break + } + } + if md == nil { + lock(&reflectOffs.lock) + res := reflectOffs.m[int32(off)] + unlock(&reflectOffs.lock) + if res == nil { + println("runtime: typeOff", hex(off), "base", hex(base), "not in ranges:") + for next := &firstmoduledata; next != nil; next = next.next { + println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) + } + throw("runtime: type offset base pointer out of range") + } + return (*_type)(res) + } + if t := md.typemap[off]; t != nil { + return t + } + res := md.types + uintptr(off) + if res > md.etypes { + println("runtime: typeOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes)) + throw("runtime: type offset out of range") + } + return (*_type)(unsafe.Pointer(res)) +} + +func (t *_type) textOff(off textOff) unsafe.Pointer { + base := uintptr(unsafe.Pointer(t)) + var md *moduledata + for next := &firstmoduledata; next != nil; next = next.next { + if base >= next.types && base < next.etypes { + md = next + break + } + } + if md == nil { + lock(&reflectOffs.lock) + res := reflectOffs.m[int32(off)] + unlock(&reflectOffs.lock) + if res == nil { + println("runtime: textOff", hex(off), "base", hex(base), "not in ranges:") + for next := &firstmoduledata; next != nil; next = next.next { + println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) + } + throw("runtime: text offset base pointer out of range") + } + return res + } + res := md.text + uintptr(off) + if res > md.etext { + println("runtime: textOff", hex(off), "out of range", hex(md.text), "-", hex(md.etext)) + throw("runtime: text offset out of range") + } + return unsafe.Pointer(res) +} + func (t *functype) in() []*_type { // See funcType in reflect/type.go for details on data layout. uadd := uintptr(unsafe.Sizeof(functype{})) @@ -154,16 +240,20 @@ func (t *functype) dotdotdot() bool { return t.outCount&(1<<15) != 0 } +type typeOff int32 +type textOff int32 + type method struct { name name - mtyp *_type - ifn unsafe.Pointer - tfn unsafe.Pointer + mtyp typeOff + ifn textOff + tfn textOff } type uncommontype struct { pkgpath *string - mhdr []method + mcount uint16 // number of methods + moff uint16 // offset from this uncommontype to [mcount]method } type imethod struct { @@ -270,6 +360,18 @@ func (n *name) name() (s string) { return s } +func (n *name) tag() (s string) { + tl := n.tagLen() + if tl == 0 { + return "" + } + nl := n.nameLen() + hdr := (*stringStruct)(unsafe.Pointer(&s)) + hdr.str = unsafe.Pointer(n.data(3 + nl + 2)) + hdr.len = tl + return s +} + func (n *name) pkgPath() *string { if *n.data(0)&(1<<2) == 0 { return nil @@ -281,3 +383,200 @@ func (n *name) pkgPath() *string { off = int(round(uintptr(off), sys.PtrSize)) return *(**string)(unsafe.Pointer(n.data(off))) } + +// typelinksinit scans the types from extra modules and builds the +// moduledata typemap used to de-duplicate type pointers. +func typelinksinit() { + if firstmoduledata.next == nil { + return + } + typehash := make(map[uint32][]*_type) + + modules := []*moduledata{} + for md := &firstmoduledata; md != nil; md = md.next { + modules = append(modules, md) + } + prev, modules := modules[len(modules)-1], modules[:len(modules)-1] + for len(modules) > 0 { + // Collect types from the previous module into typehash. + collect: + for _, tl := range prev.typelinks { + var t *_type + if prev.typemap == nil { + t = (*_type)(unsafe.Pointer(prev.types + uintptr(tl))) + } else { + t = prev.typemap[typeOff(tl)] + } + // Add to typehash if not seen before. + tlist := typehash[t.hash] + for _, tcur := range tlist { + if tcur == t { + continue collect + } + } + typehash[t.hash] = append(tlist, t) + } + + // If any of this module's typelinks match a type from a + // prior module, prefer that prior type by adding the offset + // to this module's typemap. + md := modules[len(modules)-1] + md.typemap = make(map[typeOff]*_type, len(md.typelinks)) + for _, tl := range md.typelinks { + t := (*_type)(unsafe.Pointer(md.types + uintptr(tl))) + for _, candidate := range typehash[t.hash] { + if typesEqual(t, candidate) { + t = candidate + break + } + } + md.typemap[typeOff(tl)] = t + } + + prev, modules = md, modules[:len(modules)-1] + } +} + +// typesEqual reports whether two types are equal. +// +// Everywhere in the runtime and reflect packages, it is assumed that +// there is exactly one *_type per Go type, so that pointer equality +// can be used to test if types are equal. There is one place that +// breaks this assumption: buildmode=shared. In this case a type can +// appear as two different pieces of memory. This is hidden from the +// runtime and reflect package by the per-module typemap built in +// typelinksinit. It uses typesEqual to map types from later modules +// back into earlier ones. +// +// Only typelinksinit needs this function. +func typesEqual(t, v *_type) bool { + if t == v { + return true + } + kind := t.kind & kindMask + if kind != v.kind&kindMask { + return false + } + if t._string != v._string { + return false + } + ut := t.uncommon() + uv := v.uncommon() + if ut != nil || uv != nil { + if ut == nil || uv == nil { + return false + } + if !pkgPathEqual(ut.pkgpath, uv.pkgpath) { + return false + } + } + if kindBool <= kind && kind <= kindComplex128 { + return true + } + switch kind { + case kindString, kindUnsafePointer: + return true + case kindArray: + at := (*arraytype)(unsafe.Pointer(t)) + av := (*arraytype)(unsafe.Pointer(v)) + return typesEqual(at.elem, av.elem) && at.len == av.len + case kindChan: + ct := (*chantype)(unsafe.Pointer(t)) + cv := (*chantype)(unsafe.Pointer(v)) + return ct.dir == cv.dir && typesEqual(ct.elem, cv.elem) + case kindFunc: + ft := (*functype)(unsafe.Pointer(t)) + fv := (*functype)(unsafe.Pointer(v)) + if ft.outCount != fv.outCount || ft.inCount != fv.inCount { + return false + } + tin, vin := ft.in(), fv.in() + for i := 0; i < len(tin); i++ { + if !typesEqual(tin[i], vin[i]) { + return false + } + } + tout, vout := ft.out(), fv.out() + for i := 0; i < len(tout); i++ { + if !typesEqual(tout[i], vout[i]) { + return false + } + } + return true + case kindInterface: + it := (*interfacetype)(unsafe.Pointer(t)) + iv := (*interfacetype)(unsafe.Pointer(v)) + if !pkgPathEqual(it.pkgpath, iv.pkgpath) { + return false + } + if len(it.mhdr) != len(iv.mhdr) { + return false + } + for i := range it.mhdr { + tm := &it.mhdr[i] + vm := &iv.mhdr[i] + if tm.name.name() != vm.name.name() { + return false + } + if !pkgPathEqual(tm.name.pkgPath(), vm.name.pkgPath()) { + return false + } + if !typesEqual(tm._type, vm._type) { + return false + } + } + return true + case kindMap: + mt := (*maptype)(unsafe.Pointer(t)) + mv := (*maptype)(unsafe.Pointer(v)) + return typesEqual(mt.key, mv.key) && typesEqual(mt.elem, mv.elem) + case kindPtr: + pt := (*ptrtype)(unsafe.Pointer(t)) + pv := (*ptrtype)(unsafe.Pointer(v)) + return typesEqual(pt.elem, pv.elem) + case kindSlice: + st := (*slicetype)(unsafe.Pointer(t)) + sv := (*slicetype)(unsafe.Pointer(v)) + return typesEqual(st.elem, sv.elem) + case kindStruct: + st := (*structtype)(unsafe.Pointer(t)) + sv := (*structtype)(unsafe.Pointer(v)) + if len(st.fields) != len(sv.fields) { + return false + } + for i := range st.fields { + tf := &st.fields[i] + vf := &sv.fields[i] + if tf.name.name() != vf.name.name() { + return false + } + if !pkgPathEqual(tf.name.pkgPath(), vf.name.pkgPath()) { + return false + } + if !typesEqual(tf.typ, vf.typ) { + return false + } + if tf.name.tag() != vf.name.tag() { + return false + } + if tf.offset != vf.offset { + return false + } + } + return true + default: + println("runtime: impossible type kind", kind) + throw("runtime: impossible type kind") + return false + } +} + +func pkgPathEqual(p, q *string) bool { + if p == q { + return true + } + if p == nil || q == nil { + return false + } + return *p == *q +} -- cgit v1.3-5-g9baa From 66afbf1010fa492fb9a266f9019f707bd09f066d Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Wed, 13 Apr 2016 10:06:12 -0400 Subject: cmd/link: use a switch for name prefix switching Minor cleanup. Change-Id: I7574f58a7e55c2bb798ebe9c7c98d36b8c258fb8 Reviewed-on: https://go-review.googlesource.com/21982 Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/cmd/link/internal/ld/symtab.go | 61 +++++++++++++------------------------- 1 file changed, 21 insertions(+), 40 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index 678ed38730..60bec0d6c9 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -384,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 @@ -436,7 +422,8 @@ func symtab() { continue } - if strings.HasPrefix(s.Name, "type.") { + switch { + case strings.HasPrefix(s.Name, "type."): if !DynlinkingGo() { s.Attr |= AttrHidden } @@ -447,23 +434,20 @@ func symtab() { s.Type = obj.STYPE s.Outer = symtype } - } - if strings.HasPrefix(s.Name, "go.typelink.") { + 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 @@ -471,21 +455,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 -- cgit v1.3-5-g9baa From 79048df2ccc2d4c2ccc4e15d481f7888d48cf440 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Wed, 6 Apr 2016 07:11:24 -0400 Subject: cmd/link: handle long symbol names Fixes #15104. Change-Id: I9ddfbbf39ef0a873b703ee3e04fbb7d1192f5f39 Reviewed-on: https://go-review.googlesource.com/21581 Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/cmd/link/internal/ld/objfile.go | 17 ++++++++++++----- src/cmd/link/link_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 src/cmd/link/link_test.go (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go index 6826737cae..b4d2a2184f 100644 --- a/src/cmd/link/internal/ld/objfile.go +++ b/src/cmd/link/internal/ld/objfile.go @@ -531,13 +531,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) @@ -546,7 +551,9 @@ 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 return s } 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 +} -- cgit v1.3-5-g9baa From 1441f76938bf61a2c8c2ed1a65082ddde0319633 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 14 Apr 2016 19:04:45 -0700 Subject: cmd: remove unnecessary type conversions CL generated mechanically with github.com/mdempsky/unconvert. Change-Id: Ic590315cbc7026163a1b3f8ea306ba35f1a53256 Reviewed-on: https://go-review.googlesource.com/22103 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Michael Hudson-Doyle --- src/cmd/asm/internal/asm/asm.go | 4 ++-- src/cmd/cgo/ast.go | 10 +++++----- src/cmd/compile/internal/s390x/peep.go | 4 ++-- src/cmd/go/http.go | 2 +- src/cmd/go/vcs.go | 4 ++-- src/cmd/internal/obj/arm64/obj7.go | 4 ++-- src/cmd/internal/obj/data.go | 2 +- src/cmd/internal/obj/mips/asm0.go | 2 +- src/cmd/internal/obj/objfile.go | 6 +++--- src/cmd/internal/obj/pcln.go | 10 +++++----- src/cmd/internal/obj/ppc64/asm9.go | 14 +++++++------- src/cmd/internal/obj/util.go | 2 +- src/cmd/internal/obj/x86/asm6.go | 16 ++++++++-------- src/cmd/internal/objfile/plan9obj.go | 2 +- src/cmd/internal/pprof/profile/legacy_profile.go | 10 +++++----- .../unvendor/golang.org/x/arch/arm/armasm/decode.go | 8 ++++---- .../unvendor/golang.org/x/arch/x86/x86asm/decode.go | 2 +- src/cmd/link/internal/amd64/asm.go | 2 +- src/cmd/link/internal/arm/asm.go | 2 +- src/cmd/link/internal/arm64/asm.go | 2 +- src/cmd/link/internal/ld/data.go | 18 +++++++++--------- src/cmd/link/internal/ld/decodesym.go | 4 ++-- src/cmd/link/internal/ld/dwarf.go | 18 +++++++++--------- src/cmd/link/internal/ld/elf.go | 2 +- src/cmd/link/internal/ld/ldelf.go | 6 +++--- src/cmd/link/internal/ld/ldmacho.go | 16 ++++++++-------- src/cmd/link/internal/ld/ldpe.go | 8 ++++---- src/cmd/link/internal/ld/lib.go | 4 ++-- src/cmd/link/internal/ld/macho.go | 4 ++-- src/cmd/link/internal/ld/objfile.go | 2 +- src/cmd/link/internal/ld/pcln.go | 4 ++-- src/cmd/link/internal/ld/pe.go | 4 ++-- src/cmd/link/internal/ld/symtab.go | 8 ++++---- src/cmd/link/internal/mips64/asm.go | 4 ++-- src/cmd/link/internal/ppc64/asm.go | 2 +- src/cmd/link/internal/x86/asm.go | 2 +- src/cmd/vet/structtag.go | 2 +- 37 files changed, 108 insertions(+), 108 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go index d674914c67..24906e2cce 100644 --- a/src/cmd/asm/internal/asm/asm.go +++ b/src/cmd/asm/internal/asm/asm.go @@ -59,7 +59,7 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) { } p.pendingLabels = p.pendingLabels[0:0] } - prog.Pc = int64(p.pc) + prog.Pc = p.pc if *flags.Debug { fmt.Println(p.histLineNum, prog) } @@ -371,7 +371,7 @@ func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) { Offset: p.getConstant(prog, op, &a[0]), } reg := int16(p.getConstant(prog, op, &a[1])) - reg, ok := p.arch.RegisterNumber("R", int16(reg)) + reg, ok := p.arch.RegisterNumber("R", reg) if !ok { p.errorf("bad register number %d", reg) return diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go index 2859d59750..823da43c1d 100644 --- a/src/cmd/cgo/ast.go +++ b/src/cmd/cgo/ast.go @@ -73,7 +73,7 @@ func (f *File) ReadGo(name string) { } for _, spec := range d.Specs { s, ok := spec.(*ast.ImportSpec) - if !ok || string(s.Path.Value) != `"C"` { + if !ok || s.Path.Value != `"C"` { continue } sawC = true @@ -106,7 +106,7 @@ func (f *File) ReadGo(name string) { ws := 0 for _, spec := range d.Specs { s, ok := spec.(*ast.ImportSpec) - if !ok || string(s.Path.Value) != `"C"` { + if !ok || s.Path.Value != `"C"` { d.Specs[ws] = spec ws++ } @@ -147,7 +147,7 @@ func commentText(g *ast.CommentGroup) string { } var pieces []string for _, com := range g.List { - c := string(com.Text) + c := com.Text // Remove comment markers. // The parser has given us exactly the comment text. switch c[1] { @@ -242,11 +242,11 @@ func (f *File) saveExport(x interface{}, context string) { return } for _, c := range n.Doc.List { - if !strings.HasPrefix(string(c.Text), "//export ") { + if !strings.HasPrefix(c.Text, "//export ") { continue } - name := strings.TrimSpace(string(c.Text[9:])) + name := strings.TrimSpace(c.Text[9:]) if name == "" { error_(c.Pos(), "export missing name") } diff --git a/src/cmd/compile/internal/s390x/peep.go b/src/cmd/compile/internal/s390x/peep.go index 86258d67da..cd6a8c5d8c 100644 --- a/src/cmd/compile/internal/s390x/peep.go +++ b/src/cmd/compile/internal/s390x/peep.go @@ -135,7 +135,7 @@ func pushback(r0 *gc.Flow) { } } - t := obj.Prog(*r0.Prog) + t := *r0.Prog for r = gc.Uniqp(r0); ; r = gc.Uniqp(r) { p0 = r.Link.Prog p := r.Prog @@ -162,7 +162,7 @@ func pushback(r0 *gc.Flow) { if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { fmt.Printf("\tafter\n") - for r := (*gc.Flow)(b); ; r = r.Link { + for r := b; ; r = r.Link { fmt.Printf("\t%v\n", r.Prog) if r == r0 { break diff --git a/src/cmd/go/http.go b/src/cmd/go/http.go index 19e1fe4f77..05ea503049 100644 --- a/src/cmd/go/http.go +++ b/src/cmd/go/http.go @@ -30,7 +30,7 @@ var httpClient = http.DefaultClient // when we're connecting to https servers that might not be there // or might be using self-signed certificates. var impatientInsecureHTTPClient = &http.Client{ - Timeout: time.Duration(5 * time.Second), + Timeout: 5 * time.Second, Transport: &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go index e3342999fa..4ff71f2168 100644 --- a/src/cmd/go/vcs.go +++ b/src/cmd/go/vcs.go @@ -253,7 +253,7 @@ func bzrResolveRepo(vcsBzr *vcsCmd, rootDir, remoteRepo string) (realRepo string return "", fmt.Errorf("unable to parse output of bzr info") } out = out[:i] - return strings.TrimSpace(string(out)), nil + return strings.TrimSpace(out), nil } // vcsSvn describes how to use Subversion. @@ -294,7 +294,7 @@ func svnRemoteRepo(vcsSvn *vcsCmd, rootDir string) (remoteRepo string, err error return "", fmt.Errorf("unable to parse output of svn info") } out = out[:i] - return strings.TrimSpace(string(out)), nil + return strings.TrimSpace(out), nil } func (v *vcsCmd) String() string { diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go index d833beeb2d..ffa1b416d6 100644 --- a/src/cmd/internal/obj/arm64/obj7.go +++ b/src/cmd/internal/obj/arm64/obj7.go @@ -250,7 +250,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) { if p.From.Type == obj.TYPE_FCONST { f32 := float32(p.From.Val.(float64)) i32 := math.Float32bits(f32) - literal := fmt.Sprintf("$f32.%08x", uint32(i32)) + literal := fmt.Sprintf("$f32.%08x", i32) s := obj.Linklookup(ctxt, literal, 0) s.Size = 4 p.From.Type = obj.TYPE_MEM @@ -263,7 +263,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) { case AFMOVD: if p.From.Type == obj.TYPE_FCONST { i64 := math.Float64bits(p.From.Val.(float64)) - literal := fmt.Sprintf("$f64.%016x", uint64(i64)) + literal := fmt.Sprintf("$f64.%016x", i64) s := obj.Linklookup(ctxt, literal, 0) s.Size = 8 p.From.Type = obj.TYPE_MEM diff --git a/src/cmd/internal/obj/data.go b/src/cmd/internal/obj/data.go index d7f0840bc1..5fe4cb10a5 100644 --- a/src/cmd/internal/obj/data.go +++ b/src/cmd/internal/obj/data.go @@ -183,7 +183,7 @@ 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 diff --git a/src/cmd/internal/obj/mips/asm0.go b/src/cmd/internal/obj/mips/asm0.go index 13e7600c21..73d6cabbcb 100644 --- a/src/cmd/internal/obj/mips/asm0.go +++ b/src/cmd/internal/obj/mips/asm0.go @@ -1024,7 +1024,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) { o1 = OP_IRR(opirr(ctxt, p.As), uint32(v), uint32(r), uint32(p.To.Reg)) case 5: /* syscall */ - o1 = uint32(oprrr(ctxt, p.As)) + o1 = oprrr(ctxt, p.As) case 6: /* beq r1,[r2],sbra */ v := int32(0) diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index 60505dfbb5..17175ebf06 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -371,9 +371,9 @@ func (w *objWriter) writeSymDebug(s *LSym) { name = "TLS" } if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) { - fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(int64(r.Add))) + fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(r.Add)) } else { - fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, int64(r.Add)) + fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, r.Add) } } } @@ -473,7 +473,7 @@ func (w *objWriter) writeSym(s *LSym) { func (w *objWriter) writeInt(sval int64) { var v uint64 - uv := (uint64(sval) << 1) ^ uint64(int64(sval>>63)) + uv := (uint64(sval) << 1) ^ uint64(sval>>63) p := w.varintbuf[:] for v = uv; v >= 0x80; v >>= 7 { p[0] = uint8(v | 0x80) diff --git a/src/cmd/internal/obj/pcln.go b/src/cmd/internal/obj/pcln.go index eca7531f3c..a086be9f66 100644 --- a/src/cmd/internal/obj/pcln.go +++ b/src/cmd/internal/obj/pcln.go @@ -64,7 +64,7 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(* if val == oldval && started != 0 { val = valfunc(ctxt, func_, val, p, 1, arg) if ctxt.Debugpcln != 0 { - fmt.Fprintf(ctxt.Bso, "%6x %6s %v\n", uint64(int64(p.Pc)), "", p) + fmt.Fprintf(ctxt.Bso, "%6x %6s %v\n", uint64(p.Pc), "", p) } continue } @@ -76,7 +76,7 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(* if p.Link != nil && p.Link.Pc == p.Pc { val = valfunc(ctxt, func_, val, p, 1, arg) if ctxt.Debugpcln != 0 { - fmt.Fprintf(ctxt.Bso, "%6x %6s %v\n", uint64(int64(p.Pc)), "", p) + fmt.Fprintf(ctxt.Bso, "%6x %6s %v\n", uint64(p.Pc), "", p) } continue } @@ -96,7 +96,7 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(* // where the 0x80 bit indicates that the integer continues. if ctxt.Debugpcln != 0 { - fmt.Fprintf(ctxt.Bso, "%6x %6d %v\n", uint64(int64(p.Pc)), val, p) + fmt.Fprintf(ctxt.Bso, "%6x %6d %v\n", uint64(p.Pc), val, p) } if started != 0 { @@ -118,7 +118,7 @@ func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(* if started != 0 { if ctxt.Debugpcln != 0 { - fmt.Fprintf(ctxt.Bso, "%6x done\n", uint64(int64(func_.Text.Pc)+func_.Size)) + fmt.Fprintf(ctxt.Bso, "%6x done\n", uint64(func_.Text.Pc+func_.Size)) } addvarint(ctxt, dst, uint32((func_.Size-pc)/int64(ctxt.Arch.MinLC))) addvarint(ctxt, dst, 0) // terminator @@ -164,7 +164,7 @@ func pctofileline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg if file == f { pcln.Lastfile = f pcln.Lastindex = int(i) - return int32(i) + return i } } pcln.File = append(pcln.File, f) diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go index e793f26803..f786f3c443 100644 --- a/src/cmd/internal/obj/ppc64/asm9.go +++ b/src/cmd/internal/obj/ppc64/asm9.go @@ -1384,7 +1384,7 @@ const ( // which relocation to use with a load or store and only supports the needed // instructions. func opform(ctxt *obj.Link, insn uint32) int { - switch uint32(insn) { + switch insn { default: ctxt.Diag("bad insn in loadform: %x", insn) case OPVCC(58, 0, 0, 0), // ld @@ -2198,9 +2198,9 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) { } v := oprrr(ctxt, p.As) t := v & (1<<10 | 1) /* OE|Rc */ - o1 = AOP_RRR(uint32(v)&^uint32(t), REGTMP, uint32(r), uint32(p.From.Reg)) + o1 = AOP_RRR(v&^t, REGTMP, uint32(r), uint32(p.From.Reg)) o2 = AOP_RRR(OP_MULLW, REGTMP, REGTMP, uint32(p.From.Reg)) - o3 = AOP_RRR(OP_SUBF|uint32(t), uint32(p.To.Reg), REGTMP, uint32(r)) + o3 = AOP_RRR(OP_SUBF|t, uint32(p.To.Reg), REGTMP, uint32(r)) if p.As == AREMU { o4 = o3 @@ -2216,9 +2216,9 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) { } v := oprrr(ctxt, p.As) t := v & (1<<10 | 1) /* OE|Rc */ - o1 = AOP_RRR(uint32(v)&^uint32(t), REGTMP, uint32(r), uint32(p.From.Reg)) + o1 = AOP_RRR(v&^t, REGTMP, uint32(r), uint32(p.From.Reg)) o2 = AOP_RRR(OP_MULLD, REGTMP, REGTMP, uint32(p.From.Reg)) - o3 = AOP_RRR(OP_SUBF|uint32(t), uint32(p.To.Reg), REGTMP, uint32(r)) + o3 = AOP_RRR(OP_SUBF|t, uint32(p.To.Reg), REGTMP, uint32(r)) case 52: /* mtfsbNx cr(n) */ v := regoff(ctxt, &p.From) & 31 @@ -2485,7 +2485,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) { ctxt.Diag("invalid offset against tls var %v", p) } o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R2, 0) - o2 = AOP_IRR(uint32(opload(ctxt, AMOVD)), uint32(p.To.Reg), uint32(p.To.Reg), 0) + o2 = AOP_IRR(opload(ctxt, AMOVD), uint32(p.To.Reg), uint32(p.To.Reg), 0) rel := obj.Addrel(ctxt.Cursym) rel.Off = int32(ctxt.Pc) rel.Siz = 8 @@ -2499,7 +2499,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) { } o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R2, 0) - o2 = AOP_IRR(uint32(opload(ctxt, AMOVD)), uint32(p.To.Reg), uint32(p.To.Reg), 0) + o2 = AOP_IRR(opload(ctxt, AMOVD), uint32(p.To.Reg), uint32(p.To.Reg), 0) rel := obj.Addrel(ctxt.Cursym) rel.Off = int32(ctxt.Pc) rel.Siz = 8 diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go index 04e6a76e1a..294cedcb0a 100644 --- a/src/cmd/internal/obj/util.go +++ b/src/cmd/internal/obj/util.go @@ -279,7 +279,7 @@ func Dconv(p *Prog, a *Addr) string { case TYPE_SHIFT: v := int(a.Offset) - op := string("<<>>->@>"[((v>>5)&3)<<1:]) + op := "<<>>->@>"[((v>>5)&3)<<1:] if v&(1<<4) != 0 { str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15) } else { diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index e806a834fd..57ef045b98 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -3308,7 +3308,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) { case Pf2, /* xmm opcode escape */ Pf3: - ctxt.AsmBuf.Put2(byte(o.prefix), Pm) + ctxt.AsmBuf.Put2(o.prefix, Pm) case Pef3: ctxt.AsmBuf.Put3(Pe, Pf3, Pm) @@ -3421,7 +3421,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) { asmand(ctxt, p, &p.From, &p.To) case Zm2_r: - ctxt.AsmBuf.Put2(byte(op), byte(o.op[z+1])) + ctxt.AsmBuf.Put2(byte(op), o.op[z+1]) asmand(ctxt, p, &p.From, &p.To) case Zm_r_xm: @@ -3531,7 +3531,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) { } ctxt.AsmBuf.Put1(byte(op)) if p.As == AXABORT { - ctxt.AsmBuf.Put1(byte(o.op[z+1])) + ctxt.AsmBuf.Put1(o.op[z+1]) } ctxt.AsmBuf.Put1(byte(vaddr(ctxt, p, a, nil))) @@ -3657,7 +3657,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) { if yt.zcase == Zcallcon { ctxt.AsmBuf.Put1(byte(op)) } else { - ctxt.AsmBuf.Put1(byte(o.op[z+1])) + ctxt.AsmBuf.Put1(o.op[z+1]) } r = obj.Addrel(ctxt.Cursym) r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len())) @@ -3667,7 +3667,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) { ctxt.AsmBuf.PutInt32(0) case Zcallind: - ctxt.AsmBuf.Put2(byte(op), byte(o.op[z+1])) + ctxt.AsmBuf.Put2(byte(op), o.op[z+1]) r = obj.Addrel(ctxt.Cursym) r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len())) r.Type = obj.R_ADDR @@ -3722,7 +3722,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) { log.Fatalf("bad code") } - ctxt.AsmBuf.Put1(byte(o.op[z+1])) + ctxt.AsmBuf.Put1(o.op[z+1]) r = obj.Addrel(ctxt.Cursym) r.Off = int32(p.Pc + int64(ctxt.AsmBuf.Len())) r.Sym = p.To.Sym @@ -3762,7 +3762,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) { v-- } - ctxt.AsmBuf.Put1(byte(o.op[z+1])) + ctxt.AsmBuf.Put1(o.op[z+1]) ctxt.AsmBuf.PutInt32(int32(v)) } @@ -3784,7 +3784,7 @@ func doasm(ctxt *obj.Link, p *obj.Prog) { if yt.zcase == Zbr { ctxt.AsmBuf.Put1(0x0f) } - ctxt.AsmBuf.Put1(byte(o.op[z+1])) + ctxt.AsmBuf.Put1(o.op[z+1]) ctxt.AsmBuf.PutInt32(0) } diff --git a/src/cmd/internal/objfile/plan9obj.go b/src/cmd/internal/objfile/plan9obj.go index 1d808f77eb..6ee389dc2e 100644 --- a/src/cmd/internal/objfile/plan9obj.go +++ b/src/cmd/internal/objfile/plan9obj.go @@ -59,7 +59,7 @@ func (f *plan9File) symbols() ([]Sym, error) { if !validSymType[s.Type] { continue } - sym := Sym{Addr: s.Value, Name: s.Name, Code: rune(s.Type)} + sym := Sym{Addr: s.Value, Name: s.Name, Code: s.Type} i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) if i < len(addrs) { sym.Size = int64(addrs[i] - s.Value) diff --git a/src/cmd/internal/pprof/profile/legacy_profile.go b/src/cmd/internal/pprof/profile/legacy_profile.go index 3d4da6b4d7..8ccfe45176 100644 --- a/src/cmd/internal/pprof/profile/legacy_profile.go +++ b/src/cmd/internal/pprof/profile/legacy_profile.go @@ -74,7 +74,7 @@ func parseGoCount(b []byte) (*Profile, error) { if m == nil { return nil, errUnrecognized } - profileType := string(m[1]) + profileType := m[1] p := &Profile{ PeriodType: &ValueType{Type: profileType, Unit: "count"}, Period: 1, @@ -99,11 +99,11 @@ func parseGoCount(b []byte) (*Profile, error) { if m == nil { return nil, errMalformed } - n, err := strconv.ParseInt(string(m[1]), 0, 64) + n, err := strconv.ParseInt(m[1], 0, 64) if err != nil { return nil, errMalformed } - fields := strings.Fields(string(m[2])) + fields := strings.Fields(m[2]) locs := make([]*Location, 0, len(fields)) for _, stk := range fields { addr, err := strconv.ParseUint(stk, 0, 64) @@ -458,7 +458,7 @@ func parseCPUSamples(b []byte, parse func(b []byte) (uint64, []byte), adjust boo } p.Sample = append(p.Sample, &Sample{ - Value: []int64{int64(count), int64(count) * int64(p.Period)}, + Value: []int64{int64(count), int64(count) * p.Period}, Location: sloc, }) } @@ -488,7 +488,7 @@ func parseHeap(b []byte) (p *Profile, err error) { var period int64 if len(header[6]) > 0 { - if period, err = strconv.ParseInt(string(header[6]), 10, 64); err != nil { + if period, err = strconv.ParseInt(header[6], 10, 64); err != nil { return nil, errUnrecognized } } diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go index 6b4d73841b..cc81dc3f50 100644 --- a/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go +++ b/src/cmd/internal/unvendor/golang.org/x/arch/arm/armasm/decode.go @@ -233,9 +233,9 @@ func decodeArg(aop instArg, x uint32) Arg { typ, count := decodeShift(x) // ROR #0 here means ROR #0, but decodeShift rewrites to RRX #1. if typ == RotateRightExt { - return Reg(Rm) + return Rm } - return RegShift{Rm, typ, uint8(count)} + return RegShift{Rm, typ, count} case arg_R_shift_R: Rm := Reg(x & (1<<4 - 1)) @@ -247,9 +247,9 @@ func decodeArg(aop instArg, x uint32) Arg { Rm := Reg(x & (1<<4 - 1)) typ, count := decodeShift(x) if typ == ShiftLeft && count == 0 { - return Reg(Rm) + return Rm } - return RegShift{Rm, typ, uint8(count)} + return RegShift{Rm, typ, count} case arg_R1_0: return Reg((x & (1<<4 - 1))) diff --git a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go index e4122c1e6d..9b3597300e 100644 --- a/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go +++ b/src/cmd/internal/unvendor/golang.org/x/arch/x86/x86asm/decode.go @@ -1041,7 +1041,7 @@ Decode: case xArgMoffs8, xArgMoffs16, xArgMoffs32, xArgMoffs64: // TODO(rsc): Can address be 64 bits? - mem = Mem{Disp: int64(immc)} + mem = Mem{Disp: immc} if segIndex >= 0 { mem.Segment = prefixToSegment(inst.Prefix[segIndex]) inst.Prefix[segIndex] |= PrefixImplicit diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index a6dce6c2c9..ab96a59151 100644 --- a/src/cmd/link/internal/amd64/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -735,7 +735,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() diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go index 1188615716..69e1d8f317 100644 --- a/src/cmd/link/internal/arm/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -649,7 +649,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() diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index d3ba5ff3f3..d8ffffa157 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -488,7 +488,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() diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index cf51b0a908..105503f6ef 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -80,7 +80,7 @@ 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 @@ -757,7 +757,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() } @@ -773,7 +773,7 @@ func blk(start *LSym, addr int64, size int64) { 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() } @@ -821,14 +821,14 @@ 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, "\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 { @@ -844,7 +844,7 @@ func Codeblk(addr int64, size int64) { } 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) } @@ -892,7 +892,7 @@ func Datblk(addr int64, size int64) { 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 { + if -cap(p) > -cap(sym.P) && (-cap(p)+cap(sym.P))%16 == 0 { fmt.Fprintf(Bso, "\n\t%.8x|", uint(addr+int64(-cap(p)+cap(sym.P)))) } fmt.Fprintf(Bso, " %.2x", p[0]) @@ -924,7 +924,7 @@ func Datblk(addr int64, size int64) { 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)) + 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) } } } @@ -1279,7 +1279,7 @@ func dodata() { 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)) + Diag("%s: initialize bounds (%d < %d)", s.Name, s.Size, len(s.P)) } } diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index 5fa8b4c81f..4725b91d01 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -53,12 +53,12 @@ func uncommonSize() int { return 2 * SysArch.PtrSize } // runtime.uncommont // Type.commonType.kind func decodetype_kind(s *LSym) uint8 { - return uint8(s.P[2*SysArch.PtrSize+7] & obj.KindMask) // 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*SysArch.PtrSize+7] & obj.KindGCProg) // 0x13 / 0x1f + return s.P[2*SysArch.PtrSize+7] & obj.KindGCProg // 0x13 / 0x1f } // Type.commonType.size diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index b1208b63a8..bec9946ec5 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -615,7 +615,7 @@ func putattr(s *LSym, abbrev int, form int, cls int, value int64, data interface Adduint8(Ctxt, s, uint8(value)) p := data.([]byte) for i := 0; int64(i) < value; i++ { - Adduint8(Ctxt, s, uint8(p[i])) + Adduint8(Ctxt, s, p[i]) } case DW_FORM_block2: // block @@ -624,7 +624,7 @@ func putattr(s *LSym, abbrev int, form int, cls int, value int64, data interface Adduint16(Ctxt, s, uint16(value)) p := data.([]byte) for i := 0; int64(i) < value; i++ { - Adduint8(Ctxt, s, uint8(p[i])) + Adduint8(Ctxt, s, p[i]) } case DW_FORM_block4: // block @@ -633,7 +633,7 @@ func putattr(s *LSym, abbrev int, form int, cls int, value int64, data interface Adduint32(Ctxt, s, uint32(value)) p := data.([]byte) for i := 0; int64(i) < value; i++ { - Adduint8(Ctxt, s, uint8(p[i])) + Adduint8(Ctxt, s, p[i]) } case DW_FORM_block: // block @@ -641,7 +641,7 @@ func putattr(s *LSym, abbrev int, form int, cls int, value int64, data interface p := data.([]byte) for i := 0; int64(i) < value; i++ { - Adduint8(Ctxt, s, uint8(p[i])) + Adduint8(Ctxt, s, p[i]) } case DW_FORM_data1: // constant @@ -1179,7 +1179,7 @@ func synthesizemaptypes(die *DWDie) { // Construct type to represent an array of BucketSize keys keyname := nameFromDIESym(keytype) dwhks := mkinternaltype(DW_ABRV_ARRAYTYPE, "[]key", keyname, "", func(dwhk *DWDie) { - newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*int64(keysize), 0) + newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*keysize, 0) t := keytype if indirect_key { t = defptrto(keytype) @@ -1193,7 +1193,7 @@ func synthesizemaptypes(die *DWDie) { // Construct type to represent an array of BucketSize values valname := nameFromDIESym(valtype) dwhvs := mkinternaltype(DW_ABRV_ARRAYTYPE, "[]val", valname, "", func(dwhv *DWDie) { - newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*int64(valsize), 0) + newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*valsize, 0) t := valtype if indirect_val { t = defptrto(valtype) @@ -1225,7 +1225,7 @@ func synthesizemaptypes(die *DWDie) { 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(SysArch.RegSize), 0) + newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize+BucketSize*keysize+BucketSize*valsize+int64(SysArch.RegSize), 0) }) // Construct hash @@ -1269,7 +1269,7 @@ func synthesizechantypes(die *DWDie) { } else { elemsize = 0 } - newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT, int64(sudogsize)+int64(elemsize), nil) + newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT, int64(sudogsize)+elemsize, nil) }) // waitq @@ -1787,7 +1787,7 @@ func writeinfo(prev *LSym) *LSym { } setuint32(Ctxt, s, 0, uint32(cusize)) - newattr(compunit, DW_AT_byte_size, DW_CLS_CONSTANT, int64(cusize), 0) + newattr(compunit, DW_AT_byte_size, DW_CLS_CONSTANT, cusize, 0) } return prev } diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 7c760775b5..02f7897db9 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -2026,7 +2026,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)) diff --git a/src/cmd/link/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go index d07a2a2c34..59e71f4dd4 100644 --- a/src/cmd/link/internal/ld/ldelf.go +++ b/src/cmd/link/internal/ld/ldelf.go @@ -500,7 +500,7 @@ func ldelf(f *bio.Reader, 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 @@ -612,7 +612,7 @@ func ldelf(f *bio.Reader, 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[:]) @@ -629,7 +629,7 @@ func ldelf(f *bio.Reader, 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[:])) diff --git a/src/cmd/link/internal/ld/ldmacho.go b/src/cmd/link/internal/ld/ldmacho.go index 8dc4033bbc..105fc137f9 100644 --- a/src/cmd/link/internal/ld/ldmacho.go +++ b/src/cmd/link/internal/ld/ldmacho.go @@ -399,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:]) @@ -460,8 +460,8 @@ func ldmacho(f *bio.Reader, 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 @@ -475,11 +475,11 @@ func ldmacho(f *bio.Reader, pkg string, length int64, pn string) { 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 diff --git a/src/cmd/link/internal/ld/ldpe.go b/src/cmd/link/internal/ld/ldpe.go index 7f7121ff94..c51479fb4e 100644 --- a/src/cmd/link/internal/ld/ldpe.go +++ b/src/cmd/link/internal/ld/ldpe.go @@ -175,14 +175,14 @@ func ldpe(f *bio.Reader, pkg string, length int64, pn string) { // TODO return error if found .cormeta // load string table - f.Seek(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 _, err := io.ReadFull(f, symbuf[:4]); err != nil { goto bad } l = Le32(symbuf[:]) peobj.snames = make([]byte, l) - f.Seek(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 _, err := io.ReadFull(f, peobj.snames); err != nil { goto bad } @@ -203,9 +203,9 @@ func ldpe(f *bio.Reader, pkg string, length int64, pn string) { peobj.pesym = make([]PeSym, peobj.fh.NumberOfSymbols) peobj.npesym = uint(peobj.fh.NumberOfSymbols) - f.Seek(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 { - f.Seek(int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0) + f.Seek(base+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0) if _, err := io.ReadFull(f, symbuf[:]); err != nil { goto bad } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index bdcc84a129..a18098e7e7 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -765,7 +765,7 @@ func nextar(bp *bio.Reader, off int64, a *ArHdr) int64 { if arsize&1 != 0 { arsize++ } - return int64(arsize) + SAR_HDR + return arsize + SAR_HDR } func objfile(lib *Library) { @@ -1953,7 +1953,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) diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index 1d9a1a9324..46cce4c331 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -703,11 +703,11 @@ func machosymtab() { Addstring(symstr, s.Extname) } else { for p = s.Extname; p != ""; p = p[1:] { - if uint8(p[0]) == 0xc2 && uint8((p[1:])[0]) == 0xb7 { + if p[0] == 0xc2 && (p[1:])[0] == 0xb7 { Adduint8(Ctxt, symstr, '.') p = p[1:] } else { - Adduint8(Ctxt, symstr, uint8(p[0])) + Adduint8(Ctxt, symstr, p[0]) } } diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go index b4d2a2184f..dffb7a3d9b 100644 --- a/src/cmd/link/internal/ld/objfile.go +++ b/src/cmd/link/internal/ld/objfile.go @@ -472,7 +472,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 { diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index 74ef8c2929..345eaa1ac2 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -179,7 +179,7 @@ func renumberfiles(ctxt *Link, files []*LSym, d *Pcdata) { 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 @@ -378,7 +378,7 @@ func pclntab() { 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) } } diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index 0204b8c8c2..8985c40588 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -877,7 +877,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: @@ -1043,7 +1043,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))) diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index 60bec0d6c9..96e8de5030 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -236,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) @@ -251,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) } diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go index ad6a1f7524..785002b02c 100644 --- a/src/cmd/link/internal/mips64/asm.go +++ b/src/cmd/link/internal/mips64/asm.go @@ -193,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() @@ -214,7 +214,7 @@ func asmb() { 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/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go index 3970f3c5f9..562e0810e0 100644 --- a/src/cmd/link/internal/ppc64/asm.go +++ b/src/cmd/link/internal/ppc64/asm.go @@ -913,7 +913,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() diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go index 19a8917ec8..5231ad1f6c 100644 --- a/src/cmd/link/internal/x86/asm.go +++ b/src/cmd/link/internal/x86/asm.go @@ -699,7 +699,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() diff --git a/src/cmd/vet/structtag.go b/src/cmd/vet/structtag.go index e8164a46f9..abff14fb1d 100644 --- a/src/cmd/vet/structtag.go +++ b/src/cmd/vet/structtag.go @@ -111,7 +111,7 @@ func validateStructTag(tag string) error { if i >= len(tag) { return errTagValueSyntax } - qvalue := string(tag[:i+1]) + qvalue := tag[:i+1] tag = tag[i+1:] if _, err := strconv.Unquote(qvalue); err != nil { -- cgit v1.3-5-g9baa From 106b9d391518fe382162559e1520a8af72564130 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Thu, 14 Apr 2016 19:44:55 -0700 Subject: cmd/internal/obj, cmd/link: random style cleanups Identified during review of golang.org/cl/22103. Change-Id: I86bab4cc17204df1e45deefdb0d0f9a8f6e17073 Reviewed-on: https://go-review.googlesource.com/22106 Run-TryBot: Matthew Dempsky TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/cmd/internal/obj/pcln.go | 13 ++++++------- src/cmd/link/internal/ld/macho.go | 23 +++-------------------- 2 files changed, 9 insertions(+), 27 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/internal/obj/pcln.go b/src/cmd/internal/obj/pcln.go index a086be9f66..b1536eb224 100644 --- a/src/cmd/internal/obj/pcln.go +++ b/src/cmd/internal/obj/pcln.go @@ -158,19 +158,18 @@ func pctofileline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg return int32(pcln.Lastindex) } - var i int32 - for i = 0; i < int32(len(pcln.File)); i++ { - file := pcln.File[i] + for i, file := range pcln.File { if file == f { pcln.Lastfile = f - pcln.Lastindex = int(i) - return i + pcln.Lastindex = i + return int32(i) } } + i := len(pcln.File) pcln.File = append(pcln.File, f) pcln.Lastfile = f - pcln.Lastindex = int(i) - return i + pcln.Lastindex = i + return int32(i) } // pctospadj computes the sp adjustment in effect. diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index 46cce4c331..e7d9fb5fe4 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -682,15 +682,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. @@ -699,20 +695,7 @@ 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 p[0] == 0xc2 && (p[1:])[0] == 0xb7 { - Adduint8(Ctxt, symstr, '.') - p = p[1:] - } else { - Adduint8(Ctxt, symstr, 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 @@ -725,7 +708,7 @@ func machosymtab() { } else { Adduint8(Ctxt, symtab, 0x0e) } - o = s + o := s for o.Outer != nil { o = o.Outer } -- cgit v1.3-5-g9baa From 3c8d6af8e02bbf230c2bef9f181d8ea393068299 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Sat, 16 Apr 2016 11:08:41 -0400 Subject: cmd/link: use -znocopyreloc when dynamic linking On ARM, use the gold linker to avoid copy relocations. https://sourceware.org/bugzilla/show_bug.cgi?id=19962 Change-Id: Icf82a38d39495d4518812713b957a03a6652c728 Reviewed-on: https://go-review.googlesource.com/22141 Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/cmd/link/internal/ld/lib.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index a18098e7e7..56a3736310 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1117,6 +1117,18 @@ 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.Family == sys.ARM { + // The GNU linker will generate COPY relocations on ARM + // even with -znocopyreloc set. Switch to gold. + // https://sourceware.org/bugzilla/show_bug.cgi?id=19962 + argv = append(argv, "-fuse-ld=gold") + } } if Iself && len(buildinfo) > 0 { -- cgit v1.3-5-g9baa From 95df0c6ab93f6a42bdc9fd45500fd4d56bfc9add Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Mon, 28 Mar 2016 21:51:10 -0400 Subject: cmd/compile, etc: use name offset in method tables Introduce and start using nameOff for two encoded names. This pair of changes is best done together because the linker's method decoder expects the method layouts to match. Precursor to converting all existing name and *string fields to nameOff. linux/amd64: cmd/go: -45KB (0.5%) jujud: -389KB (0.6%) linux/amd64 PIE: cmd/go: -170KB (1.4%) jujud: -1.5MB (1.8%) For #6853. Change-Id: Ia044423f010fb987ce070b94c46a16fc78666ff6 Reviewed-on: https://go-review.googlesource.com/21396 Reviewed-by: Ian Lance Taylor --- src/cmd/compile/internal/gc/reflect.go | 14 ++--- src/cmd/link/internal/ld/decodesym.go | 18 +++---- src/cmd/link/internal/ld/symtab.go | 2 +- src/reflect/export_test.go | 8 +-- src/reflect/type.go | 96 +++++++++++++++++++++------------- src/reflect/value.go | 8 +-- src/runtime/iface.go | 17 +++--- src/runtime/runtime1.go | 6 +++ src/runtime/type.go | 46 ++++++++++------ 9 files changed, 130 insertions(+), 85 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index b8b9369f37..f782ce0974 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -70,7 +70,7 @@ const ( ) func structfieldSize() int { return 3 * Widthptr } // Sizeof(runtime.structfield{}) -func imethodSize() int { return 2 * Widthptr } // Sizeof(runtime.imethod{}) +func imethodSize() int { return 4 + 4 } // Sizeof(runtime.imethod{}) func uncommonSize(t *Type) int { // Sizeof(runtime.uncommontype{}) if t.Sym == nil && len(methods(t)) == 0 { return 0 @@ -647,13 +647,11 @@ func dextratypeData(s *Sym, ot int, t *Type) int { pkg = a.pkg } nsym := dname(a.name, "", pkg, exported) - ot = dsymptrLSym(lsym, ot, nsym, 0) + + ot = dsymptrOffLSym(lsym, ot, nsym, 0) ot = dmethodptrOffLSym(lsym, ot, Linksym(dtypesym(a.mtype))) ot = dmethodptrOffLSym(lsym, ot, Linksym(a.isym)) ot = dmethodptrOffLSym(lsym, ot, Linksym(a.tsym)) - if Widthptr == 8 { - ot = duintxxLSym(lsym, ot, 0, 4) // pad to reflect.method size - } } return ot } @@ -1226,6 +1224,7 @@ ok: dataAdd := imethodSize() * n ot = dextratype(s, ot, t, dataAdd) + lsym := Linksym(s) for _, a := range m { // ../../../../runtime/type.go:/imethod exported := exportname(a.name) @@ -1234,8 +1233,9 @@ ok: pkg = a.pkg } nsym := dname(a.name, "", pkg, exported) - ot = dsymptrLSym(Linksym(s), ot, nsym, 0) - ot = dsymptr(s, ot, dtypesym(a.type_), 0) + + ot = dsymptrOffLSym(lsym, ot, nsym, 0) + ot = dsymptrOffLSym(lsym, ot, Linksym(dtypesym(a.type_)), 0) } // ../../../../runtime/type.go:/mapType diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index 4725b91d01..5eb20c2fb2 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -262,8 +262,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 { @@ -271,7 +272,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+SysArch.PtrSize)) + mtypSym := decode_reloc_sym(s, int32(off+4)) buf.WriteRune('(') inCount := decodetype_funcincount(mtypSym) @@ -311,7 +312,7 @@ func decodetype_ifacemethods(s *LSym) []methodsig { } off := int(r.Add) // array of reflect.imethod values numMethods := int(decodetype_ifacemethodcount(s)) - sizeofIMethod := 2 * SysArch.PtrSize + sizeofIMethod := 4 + 4 return decode_methodsig(s, off, sizeofIMethod, numMethods) } @@ -343,12 +344,7 @@ func decodetype_methods(s *LSym) []methodsig { mcount := int(decode_inuxi(s.P[off+SysArch.PtrSize:], 2)) moff := int(decode_inuxi(s.P[off+SysArch.PtrSize+2:], 2)) - off += moff // offset to array of reflect.method values - var sizeofMethod int // sizeof reflect.method in program - if SysArch.PtrSize == 4 { - sizeofMethod = 4 * SysArch.PtrSize - } else { - sizeofMethod = 3 * SysArch.PtrSize - } + 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/symtab.go b/src/cmd/link/internal/ld/symtab.go index 96e8de5030..1f07a4eb77 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -427,7 +427,7 @@ func symtab() { if !DynlinkingGo() { s.Attr |= AttrHidden } - if UseRelro() && len(s.R) > 0 { + if UseRelro() { s.Type = obj.STYPERELRO s.Outer = symtyperel } else { diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go index 2769e0db40..f527434f0d 100644 --- a/src/reflect/export_test.go +++ b/src/reflect/export_test.go @@ -50,7 +50,8 @@ func TypeLinks() []string { for i, offs := range offset { rodata := sections[i] for _, off := range offs { - r = append(r, rtypeOff(rodata, off).string) + typ := (*rtype)(resolveTypeOff(unsafe.Pointer(rodata), off)) + r = append(r, typ.string) } } return r @@ -91,10 +92,11 @@ func FirstMethodNameBytes(t Type) *byte { panic("type has no methods") } m := ut.methods()[0] - if *m.name.data(0)&(1<<2) == 0 { + mname := t.(*rtype).nameOff(m.name) + if *mname.data(0)&(1<<2) == 0 { panic("method name does not have pkgPath *string") } - return m.name.bytes + return mname.bytes } type OtherPkgFields struct { diff --git a/src/reflect/type.go b/src/reflect/type.go index b8c778cc2b..0cae69a79c 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -288,7 +288,7 @@ type typeAlg struct { // Method on non-interface type type method struct { - name name // name of method + name nameOff // name of method mtyp typeOff // method type (without receiver) ifn textOff // fn used in interface call (one-word receiver) tfn textOff // fn used for normal method call @@ -347,8 +347,8 @@ type funcType struct { // imethod represents a method on an interface type type imethod struct { - name name // name of method - typ *rtype // .(*FuncType) underneath + name nameOff // name of method + typ typeOff // .(*FuncType) underneath } // interfaceType represents an interface type. @@ -424,19 +424,19 @@ type name struct { bytes *byte } -func (n *name) data(off int) *byte { +func (n name) data(off int) *byte { return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off))) } -func (n *name) isExported() bool { +func (n name) isExported() bool { return (*n.bytes)&(1<<0) != 0 } -func (n *name) nameLen() int { +func (n name) nameLen() int { return int(uint16(*n.data(1))<<8 | uint16(*n.data(2))) } -func (n *name) tagLen() int { +func (n name) tagLen() int { if *n.data(0)&(1<<1) == 0 { return 0 } @@ -444,7 +444,7 @@ func (n *name) tagLen() int { return int(uint16(*n.data(off))<<8 | uint16(*n.data(off + 1))) } -func (n *name) name() (s string) { +func (n name) name() (s string) { if n.bytes == nil { return "" } @@ -458,7 +458,7 @@ func (n *name) name() (s string) { return s } -func (n *name) tag() (s string) { +func (n name) tag() (s string) { tl := n.tagLen() if tl == 0 { return "" @@ -470,7 +470,7 @@ func (n *name) tag() (s string) { return s } -func (n *name) pkgPath() string { +func (n name) pkgPath() string { if n.bytes == nil || *n.data(0)&(1<<2) == 0 { return "" } @@ -480,7 +480,7 @@ func (n *name) pkgPath() string { } var nameOff int32 copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off)))[:]) - pkgPathName := name{(*byte)(resolveTypeOff(unsafe.Pointer(n), nameOff))} + pkgPathName := name{(*byte)(resolveTypeOff(unsafe.Pointer(n.bytes), nameOff))} return pkgPathName.name() } @@ -605,6 +605,11 @@ func (t *uncommonType) PkgPath() string { return t.pkgPath.name() } +// resolveNameOff resolves a name offset from a base pointer. +// The (*rtype).nameOff method is a convenience wrapper for this function. +// Implemented in the runtime package. +func resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer + // resolveTypeOff resolves an *rtype offset from a base type. // The (*rtype).typeOff method is a convenience wrapper for this function. // Implemented in the runtime package. @@ -620,6 +625,12 @@ func resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer // be resolved correctly. Implemented in the runtime package. func addReflectOff(ptr unsafe.Pointer) int32 +// resolveReflectType adds a name to the reflection lookup map in the runtime. +// It returns a new nameOff that can be used to refer to the pointer. +func resolveReflectName(n name) nameOff { + return nameOff(addReflectOff(unsafe.Pointer(n.bytes))) +} + // resolveReflectType adds a *rtype to the reflection lookup map in the runtime. // It returns a new typeOff that can be used to refer to the pointer. func resolveReflectType(t *rtype) typeOff { @@ -633,9 +644,17 @@ func resolveReflectText(ptr unsafe.Pointer) textOff { return textOff(addReflectOff(ptr)) } +type nameOff int32 // offset to a name type typeOff int32 // offset to an *rtype type textOff int32 // offset from top of text section +func (t *rtype) nameOff(off nameOff) name { + if off == 0 { + return name{} + } + return name{(*byte)(resolveNameOff(unsafe.Pointer(t), int32(off)))} +} + func (t *rtype) typeOff(off typeOff) *rtype { if off == 0 { return nil @@ -753,10 +772,11 @@ func (t *rtype) Method(i int) (m Method) { panic("reflect: Method index out of range") } p := ut.methods()[i] - m.Name = p.name.name() + pname := t.nameOff(p.name) + m.Name = pname.name() fl := flag(Func) - if !p.name.isExported() { - m.PkgPath = p.name.pkgPath() + if !pname.isExported() { + m.PkgPath = pname.pkgPath() if m.PkgPath == "" { m.PkgPath = ut.pkgPath.name() } @@ -796,7 +816,8 @@ func (t *rtype) MethodByName(name string) (m Method, ok bool) { utmethods := ut.methods() for i := 0; i < int(ut.mcount); i++ { p := utmethods[i] - if p.name.name() == name { + pname := t.nameOff(p.name) + if pname.name() == name { return t.Method(i), true } } @@ -1005,14 +1026,15 @@ func (t *interfaceType) Method(i int) (m Method) { return } p := &t.methods[i] - m.Name = p.name.name() - if !p.name.isExported() { - m.PkgPath = p.name.pkgPath() + pname := t.nameOff(p.name) + m.Name = pname.name() + if !pname.isExported() { + m.PkgPath = pname.pkgPath() if m.PkgPath == "" { m.PkgPath = t.pkgPath.name() } } - m.Type = toType(p.typ) + m.Type = toType(t.typeOff(p.typ)) m.Index = i return } @@ -1028,7 +1050,7 @@ func (t *interfaceType) MethodByName(name string) (m Method, ok bool) { var p *imethod for i := range t.methods { p = &t.methods[i] - if p.name.name() == name { + if t.nameOff(p.name).name() == name { return t.Method(i), true } } @@ -1468,7 +1490,7 @@ func implements(T, V *rtype) bool { for j := 0; j < len(v.methods); j++ { tm := &t.methods[i] vm := &v.methods[j] - if vm.name.name() == tm.name.name() && vm.typ == tm.typ { + if V.nameOff(vm.name).name() == t.nameOff(tm.name).name() && V.typeOff(vm.typ) == t.typeOff(tm.typ) { if i++; i >= len(t.methods) { return true } @@ -1486,7 +1508,7 @@ func implements(T, V *rtype) bool { for j := 0; j < int(v.mcount); j++ { tm := &t.methods[i] vm := vmethods[j] - if vm.name.name() == tm.name.name() && V.typeOff(vm.mtyp) == tm.typ { + if V.nameOff(vm.name).name() == t.nameOff(tm.name).name() && V.typeOff(vm.mtyp) == t.typeOff(tm.typ) { if i++; i >= len(t.methods) { return true } @@ -2327,12 +2349,13 @@ func StructOf(fields []StructField) Type { case Interface: ift := (*interfaceType)(unsafe.Pointer(ft)) for im, m := range ift.methods { - if m.name.pkgPath() != "" { + if ift.nameOff(m.name).pkgPath() != "" { // TODO(sbinet) panic("reflect: embedded interface with unexported method(s) not implemented") } var ( + mtyp = ift.typeOff(m.typ) ifield = i imethod = im ifn Value @@ -2340,7 +2363,7 @@ func StructOf(fields []StructField) Type { ) if ft.kind&kindDirectIface != 0 { - tfn = MakeFunc(m.typ, func(in []Value) []Value { + tfn = MakeFunc(mtyp, func(in []Value) []Value { var args []Value var recv = in[0] if len(in) > 1 { @@ -2348,7 +2371,7 @@ func StructOf(fields []StructField) Type { } return recv.Field(ifield).Method(imethod).Call(args) }) - ifn = MakeFunc(m.typ, func(in []Value) []Value { + ifn = MakeFunc(mtyp, func(in []Value) []Value { var args []Value var recv = in[0] if len(in) > 1 { @@ -2357,7 +2380,7 @@ func StructOf(fields []StructField) Type { return recv.Field(ifield).Method(imethod).Call(args) }) } else { - tfn = MakeFunc(m.typ, func(in []Value) []Value { + tfn = MakeFunc(mtyp, func(in []Value) []Value { var args []Value var recv = in[0] if len(in) > 1 { @@ -2365,7 +2388,7 @@ func StructOf(fields []StructField) Type { } return recv.Field(ifield).Method(imethod).Call(args) }) - ifn = MakeFunc(m.typ, func(in []Value) []Value { + ifn = MakeFunc(mtyp, func(in []Value) []Value { var args []Value var recv = Indirect(in[0]) if len(in) > 1 { @@ -2376,8 +2399,8 @@ func StructOf(fields []StructField) Type { } methods = append(methods, method{ - name: m.name, - mtyp: resolveReflectType(m.typ), + name: resolveReflectName(ift.nameOff(m.name)), + mtyp: resolveReflectType(mtyp), ifn: resolveReflectText(unsafe.Pointer(&ifn)), tfn: resolveReflectText(unsafe.Pointer(&tfn)), }) @@ -2386,12 +2409,13 @@ func StructOf(fields []StructField) Type { ptr := (*ptrType)(unsafe.Pointer(ft)) if unt := ptr.uncommon(); unt != nil { for _, m := range unt.methods() { - if m.name.pkgPath() != "" { + mname := ptr.nameOff(m.name) + if mname.pkgPath() != "" { // TODO(sbinet) panic("reflect: embedded interface with unexported method(s) not implemented") } methods = append(methods, method{ - name: m.name, + name: resolveReflectName(mname), mtyp: resolveReflectType(ptr.typeOff(m.mtyp)), ifn: resolveReflectText(ptr.textOff(m.ifn)), tfn: resolveReflectText(ptr.textOff(m.tfn)), @@ -2400,12 +2424,13 @@ func StructOf(fields []StructField) Type { } if unt := ptr.elem.uncommon(); unt != nil { for _, m := range unt.methods() { - if m.name.pkgPath() != "" { + mname := ptr.nameOff(m.name) + if mname.pkgPath() != "" { // TODO(sbinet) panic("reflect: embedded interface with unexported method(s) not implemented") } methods = append(methods, method{ - name: m.name, + name: resolveReflectName(mname), mtyp: resolveReflectType(ptr.elem.typeOff(m.mtyp)), ifn: resolveReflectText(ptr.elem.textOff(m.ifn)), tfn: resolveReflectText(ptr.elem.textOff(m.tfn)), @@ -2415,12 +2440,13 @@ func StructOf(fields []StructField) Type { default: if unt := ft.uncommon(); unt != nil { for _, m := range unt.methods() { - if m.name.pkgPath() != "" { + mname := ft.nameOff(m.name) + if mname.pkgPath() != "" { // TODO(sbinet) panic("reflect: embedded interface with unexported method(s) not implemented") } methods = append(methods, method{ - name: m.name, + name: resolveReflectName(mname), mtyp: resolveReflectType(ft.typeOff(m.mtyp)), ifn: resolveReflectText(ft.textOff(m.ifn)), tfn: resolveReflectText(ft.textOff(m.tfn)), diff --git a/src/reflect/value.go b/src/reflect/value.go index d4d317436a..e6b846e5d1 100644 --- a/src/reflect/value.go +++ b/src/reflect/value.go @@ -553,7 +553,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn panic("reflect: internal error: invalid method index") } m := &tt.methods[i] - if !m.name.isExported() { + if !tt.nameOff(m.name).isExported() { panic("reflect: " + op + " of unexported method") } iface := (*nonEmptyInterface)(v.ptr) @@ -562,7 +562,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn } rcvrtype = iface.itab.typ fn = unsafe.Pointer(&iface.itab.fun[i]) - t = m.typ + t = tt.typeOff(m.typ) } else { rcvrtype = v.typ ut := v.typ.uncommon() @@ -570,7 +570,7 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype, t *rtype, fn panic("reflect: internal error: invalid method index") } m := ut.methods()[i] - if !m.name.isExported() { + if !v.typ.nameOff(m.name).isExported() { panic("reflect: " + op + " of unexported method") } ifn := v.typ.textOff(m.ifn) @@ -1684,7 +1684,7 @@ func (v Value) Type() Type { panic("reflect: internal error: invalid method index") } m := &tt.methods[i] - return m.typ + return v.typ.typeOff(m.typ) } // Method on concrete type. ut := v.typ.uncommon() diff --git a/src/runtime/iface.go b/src/runtime/iface.go index 84f0ee8f0c..8f179bac80 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -37,7 +37,8 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab { if canfail { return nil } - panic(&TypeAssertionError{"", typ._string, inter.typ._string, inter.mhdr[0].name.name()}) + name := inter.typ.nameOff(inter.mhdr[0].name) + panic(&TypeAssertionError{"", typ._string, inter.typ._string, name.name()}) } h := itabhash(inter, typ) @@ -98,20 +99,22 @@ func additab(m *itab, locked, canfail bool) { j := 0 for k := 0; k < ni; k++ { i := &inter.mhdr[k] - iname := i.name.name() - itype := i._type - ipkg := i.name.pkgPath() + itype := inter.typ.typeOff(i.ityp) + name := inter.typ.nameOff(i.name) + iname := name.name() + ipkg := name.pkgPath() if ipkg == "" { ipkg = inter.pkgpath.name() } for ; j < nt; j++ { t := &xmhdr[j] - if typ.typeOff(t.mtyp) == itype && t.name.name() == iname { - pkgPath := t.name.pkgPath() + tname := typ.nameOff(t.name) + if typ.typeOff(t.mtyp) == itype && tname.name() == iname { + pkgPath := tname.pkgPath() if pkgPath == "" { pkgPath = x.pkgpath.name() } - if t.name.isExported() || pkgPath == ipkg { + if tname.isExported() || pkgPath == ipkg { if m != nil { ifn := typ.textOff(t.ifn) *(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = ifn diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go index 02aeedaf75..9089383904 100644 --- a/src/runtime/runtime1.go +++ b/src/runtime/runtime1.go @@ -487,6 +487,12 @@ func reflect_typelinks() ([]unsafe.Pointer, [][]int32) { return sections, ret } +// reflect_resolveNameOff resolves a name offset from a base pointer. +//go:linkname reflect_resolveNameOff reflect.resolveNameOff +func reflect_resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer { + return unsafe.Pointer(resolveNameOff(ptrInModule, nameOff(off)).bytes) +} + // reflect_resolveTypeOff resolves an *rtype offset from a base type. //go:linkname reflect_resolveTypeOff reflect.resolveTypeOff func reflect_resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer { diff --git a/src/runtime/type.go b/src/runtime/type.go index 711753bab5..31f7ff81b8 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -161,11 +161,17 @@ func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name { } } if md == nil { - println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:") - for next := &firstmoduledata; next != nil; next = next.next { - println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) + lock(&reflectOffs.lock) + res, found := reflectOffs.m[int32(off)] + unlock(&reflectOffs.lock) + if !found { + println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:") + for next := &firstmoduledata; next != nil; next = next.next { + println("\ttypes", hex(next.types), "etypes", hex(next.etypes)) + } + throw("runtime: name offset base pointer out of range") } - throw("runtime: name offset base pointer out of range") + return name{(*byte)(res)} } res := md.types + uintptr(off) if res > md.etypes { @@ -175,6 +181,10 @@ func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name { return name{(*byte)(unsafe.Pointer(res))} } +func (t *_type) nameOff(off nameOff) name { + return resolveNameOff(unsafe.Pointer(t), off) +} + func (t *_type) typeOff(off typeOff) *_type { if off == 0 { return nil @@ -269,7 +279,7 @@ type typeOff int32 type textOff int32 type method struct { - name name + name nameOff mtyp typeOff ifn textOff tfn textOff @@ -282,8 +292,8 @@ type uncommontype struct { } type imethod struct { - name name - _type *_type + name nameOff + ityp typeOff } type interfacetype struct { @@ -354,19 +364,19 @@ type name struct { bytes *byte } -func (n *name) data(off int) *byte { +func (n name) data(off int) *byte { return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off))) } -func (n *name) isExported() bool { +func (n name) isExported() bool { return (*n.bytes)&(1<<0) != 0 } -func (n *name) nameLen() int { +func (n name) nameLen() int { return int(uint16(*n.data(1))<<8 | uint16(*n.data(2))) } -func (n *name) tagLen() int { +func (n name) tagLen() int { if *n.data(0)&(1<<1) == 0 { return 0 } @@ -374,7 +384,7 @@ func (n *name) tagLen() int { return int(uint16(*n.data(off))<<8 | uint16(*n.data(off + 1))) } -func (n *name) name() (s string) { +func (n name) name() (s string) { if n.bytes == nil { return "" } @@ -388,7 +398,7 @@ func (n *name) name() (s string) { return s } -func (n *name) tag() (s string) { +func (n name) tag() (s string) { tl := n.tagLen() if tl == 0 { return "" @@ -400,7 +410,7 @@ func (n *name) tag() (s string) { return s } -func (n *name) pkgPath() string { +func (n name) pkgPath() string { if n.bytes == nil || *n.data(0)&(1<<2) == 0 { return "" } @@ -545,13 +555,15 @@ func typesEqual(t, v *_type) bool { for i := range it.mhdr { tm := &it.mhdr[i] vm := &iv.mhdr[i] - if tm.name.name() != vm.name.name() { + tname := it.typ.nameOff(tm.name) + vname := iv.typ.nameOff(vm.name) + if tname.name() != vname.name() { return false } - if tm.name.pkgPath() != vm.name.pkgPath() { + if tname.pkgPath() != vname.pkgPath() { return false } - if !typesEqual(tm._type, vm._type) { + if !typesEqual(it.typ.typeOff(tm.ityp), iv.typ.typeOff(vm.ityp)) { return false } } -- cgit v1.3-5-g9baa From a3c92c9db137413b17447a72c334c3e560bace06 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Mon, 18 Apr 2016 07:24:48 -0400 Subject: cmd/link: use gold when dynamic linking on arm64 The GNU linker follows the letter of -znocopyreloc by refusing to generate COPY relocations on arm64. Unfortunately it generates an error instead of finding another way. The gold linker works, so switch to it. Fixes linux/arm64 build. Change-Id: I1f7119d999c8f9f1f2d0c1e06b6462cea9c02a71 Reviewed-on: https://go-review.googlesource.com/22185 Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- misc/cgo/testshared/shared_test.go | 10 +++++----- src/cmd/link/internal/ld/lib.go | 11 ++++++++--- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'src/cmd/link') diff --git a/misc/cgo/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go index abe831a324..c370f7b0d8 100644 --- a/misc/cgo/testshared/shared_test.go +++ b/misc/cgo/testshared/shared_test.go @@ -329,21 +329,21 @@ func readNotes(f *elf.File) ([]*note, error) { return notes, nil } -func dynStrings(path string, flag elf.DynTag) []string { +func dynStrings(t *testing.T, path string, flag elf.DynTag) []string { f, err := elf.Open(path) defer f.Close() if err != nil { - log.Fatal("elf.Open failed: ", err) + t.Fatalf("elf.Open(%q) failed: %v", path, err) } dynstrings, err := f.DynString(flag) if err != nil { - log.Fatal("dynstring failed: ", err) + t.Fatalf("DynString(%s) failed on %s: %v", flag, path, err) } return dynstrings } func AssertIsLinkedToRegexp(t *testing.T, path string, re *regexp.Regexp) { - for _, dynstring := range dynStrings(path, elf.DT_NEEDED) { + for _, dynstring := range dynStrings(t, path, elf.DT_NEEDED) { if re.MatchString(dynstring) { return } @@ -357,7 +357,7 @@ func AssertIsLinkedTo(t *testing.T, path, lib string) { func AssertHasRPath(t *testing.T, path, dir string) { for _, tag := range []elf.DynTag{elf.DT_RPATH, elf.DT_RUNPATH} { - for _, dynstring := range dynStrings(path, tag) { + for _, dynstring := range dynStrings(t, path, tag) { for _, rpath := range strings.Split(dynstring, ":") { if filepath.Clean(rpath) == filepath.Clean(dir) { return diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 56a3736310..24cdca5a3b 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1123,10 +1123,15 @@ func hostlink() { // from the beginning of the section (like STYPE). argv = append(argv, "-Wl,-znocopyreloc") - if SysArch.Family == sys.ARM { - // The GNU linker will generate COPY relocations on ARM - // even with -znocopyreloc set. Switch to gold. + 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") } } -- cgit v1.3-5-g9baa From 4140da7b57f944cc16324496adcc5a41d7a987ed Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Mon, 4 Apr 2016 13:07:24 -0400 Subject: cmd/link, cmd/compile: typelink sorting in linker Instead of writing out the type almost twice in the symbol name, teach the linker how to sort typelink symbols by their contents. This ~halves the size of typelink symbol names, which helps very large (6KB) names like those mentioned in #15104. This does not increase the total sorting work done by the linker, and makes it possible to use shorter symbol names for types. See the follow-on CL 21583. Change-Id: Ie5807565ed07d31bc477d20f60e4c0b47144f337 Reviewed-on: https://go-review.googlesource.com/21457 Reviewed-by: Ian Lance Taylor --- src/cmd/compile/internal/gc/reflect.go | 11 +---------- src/cmd/link/internal/ld/data.go | 8 ++++++++ src/cmd/link/internal/ld/decodesym.go | 12 ++++++++++++ 3 files changed, 21 insertions(+), 10 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index f782ce0974..5031045c64 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -912,16 +912,7 @@ func tracksym(t *Type, f *Field) *Sym { } func typelinkLSym(t *Type) *obj.LSym { - // %-uT is what the generated Type's string field says. - // It uses (ambiguous) package names instead of import paths. - // %-T is the complete, unambiguous type name. - // We want the types to end up sorted by string field, - // so use that first in the name, and then add :%-T to - // disambiguate. We use a tab character as the separator to - // ensure the types appear sorted by their string field. The - // names are a little long but they are discarded by the linker - // and do not end up in the symbol table of the final binary. - name := "go.typelink." + Tconv(t, FmtLeft|FmtUnsigned) + "\t" + Tconv(t, FmtLeft) + name := "go.typelink." + Tconv(t, FmtLeft) // complete, unambiguous type name return obj.Linklookup(Ctxt, name, 0) } diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 105503f6ef..8e2cf99877 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -32,6 +32,7 @@ package ld import ( + "bytes" "cmd/internal/gcprog" "cmd/internal/obj" "cmd/internal/sys" @@ -1199,6 +1200,13 @@ func (d dataSlice) Less(i, j int) bool { return s1.Size < s2.Size } + // Sort typelinks by the string field. + if strings.HasPrefix(s1.Name, "go.typelink.") && strings.HasPrefix(s2.Name, "go.typelink.") { + s1n := decodetype_string(s1.Lsym.R[0].Sym) + s2n := decodetype_string(s2.Lsym.R[0].Sym) + return bytes.Compare(s1n, s2n) < 0 + } + return s1.Name < s2.Name } diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index 5eb20c2fb2..b1c55cf787 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -211,6 +211,18 @@ func decodetype_structfieldarrayoff(s *LSym, i int) int { return off } +// decodetype_string returns the contents of an rtype's string field. +func decodetype_string(s *LSym) []byte { + off := 4*SysArch.PtrSize + 8 + strlen := int64(decode_inuxi(s.P[off+SysArch.PtrSize:], SysArch.IntSize)) + + r := decode_reloc(s, int32(off)) + if r == nil { + return nil + } + return r.Sym.P[r.Add : r.Add+strlen] +} + // decodetype_name decodes the name from a reflect.name. func decodetype_name(s *LSym, off int) string { r := decode_reloc(s, int32(off)) -- cgit v1.3-5-g9baa From f81ae3b22ca9cab78251b38fe52eacfea57e08f5 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Wed, 6 Apr 2016 13:09:06 -0400 Subject: cmd/link: shorter type symbol names Use (part of) a SHA-1 checksum to replace type symbol names. In typical programs this has no effect because types are not included in the symbol table. But when dynamically linking, types are in the table to make sure there is only one *rtype per Go type. Eventually we may be able to get rid of all pointers to rtype values in the binary, but probably not by 1.7. And this has a nice effect on binary size today: libstd.so: before 27.4MB after 26.2MB For #6853. Change-Id: I603d7f3e5baad84f59f2fd37eeb1e4ae5acfe44a Reviewed-on: https://go-review.googlesource.com/21583 Reviewed-by: Brad Fitzpatrick Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/objfile.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go index dffb7a3d9b..566c949040 100644 --- a/src/cmd/link/internal/ld/objfile.go +++ b/src/cmd/link/internal/ld/objfile.go @@ -112,6 +112,8 @@ import ( "bytes" "cmd/internal/bio" "cmd/internal/obj" + "crypto/sha1" + "encoding/base64" "io" "log" "strconv" @@ -555,6 +557,28 @@ func (r *objReader) readSymName() string { 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]...) -- cgit v1.3-5-g9baa From 1dad218da1239a8375b7fad5dd83e4a840e3fdbb Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Wed, 20 Apr 2016 10:36:27 -0400 Subject: cmd/link: move declarations into loops (Split out from CL 22205.) Change-Id: Id32698f48ce02b55c15b6f2842215e0ffdbf425b Reviewed-on: https://go-review.googlesource.com/22298 Reviewed-by: Brad Fitzpatrick Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/elf.go | 6 ++---- src/cmd/link/internal/ld/macho.go | 6 ++---- src/cmd/link/internal/ld/pe.go | 6 ++---- 3 files changed, 6 insertions(+), 12 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 02f7897db9..15f0656aea 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -1692,8 +1692,6 @@ func elfrelocsect(sect *Section, first *LSym) { } eaddr := int32(sect.Vaddr + sect.Length) - var r *Reloc - var ri int for ; sym != nil; sym = sym.Next { if !sym.Attr.Reachable() { continue @@ -1703,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 } diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index e7d9fb5fe4..6ca5ba5861 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -824,8 +824,6 @@ func machorelocsect(sect *Section, first *LSym) { } eaddr := int32(sect.Vaddr + sect.Length) - var r *Reloc - var ri int for ; sym != nil; sym = sym.Next { if !sym.Attr.Reachable() { continue @@ -835,8 +833,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 } diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index 8985c40588..3b477fd846 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -784,8 +784,6 @@ func perelocsect(sect *Section, first *LSym) int { } eaddr := int32(sect.Vaddr + sect.Length) - var r *Reloc - var ri int for ; sym != nil; sym = sym.Next { if !sym.Attr.Reachable() { continue @@ -795,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 } -- cgit v1.3-5-g9baa From 854ab14b7e20a419620a42b837a9cf45cbca8189 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Wed, 20 Apr 2016 14:22:20 -0400 Subject: cmd/link: move pcln declarations into loops (Split out from CL 22243.) Change-Id: Idac1748c8db2b2ed0484e4afadb105c471c6ce34 Reviewed-on: https://go-review.googlesource.com/22321 Reviewed-by: Brad Fitzpatrick Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/pcln.go | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index 345eaa1ac2..e1c1d2d318 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -158,16 +158,12 @@ func renumberfiles(ctxt *Link, files []*LSym, d *Pcdata) { 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 { @@ -177,9 +173,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(dv>>31) + v := (uint32(dv) << 1) ^ uint32(dv>>31) addvarint(&out, v) // pc delta @@ -250,18 +246,12 @@ func pclntab() { nfunc = 0 var last *LSym - var end int32 - var funcstart int32 - var i int32 - var it Pciter - var off int32 - var pcln *FuncInfo for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next { last = Ctxt.Cursym if container(Ctxt.Cursym) != 0 { continue } - pcln = Ctxt.Cursym.FuncInfo + pcln := Ctxt.Cursym.FuncInfo if pcln == nil { pcln = &pclntab_zpcln } @@ -270,16 +260,16 @@ func pclntab() { pclntabFirstFunc = Ctxt.Cursym } - funcstart = int32(len(ftab.P)) + funcstart := int32(len(ftab.P)) funcstart += int32(-len(ftab.P)) & (int32(SysArch.PtrSize) - 1) 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(SysArch.PtrSize) + 3*4 + 5*4 + int32(len(pcln.Pcdata))*4 + int32(len(pcln.Funcdata))*int32(SysArch.PtrSize) + 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 } @@ -310,6 +300,7 @@ 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) @@ -326,7 +317,7 @@ 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]) } @@ -336,7 +327,7 @@ func pclntab() { 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(SysArch.PtrSize)*int64(i), uint64(pcln.Funcdataoff[i]), int64(SysArch.PtrSize)) } else { -- cgit v1.3-5-g9baa From 79c527f4a7643b6cc9e49f5e919d6f4a44f492ca Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Wed, 20 Apr 2016 14:40:18 -0400 Subject: cmd/link: move ppc64 genplt declarations into loop (Split out from CL 22243.) Change-Id: I07709a0c417e7a57e839e5085a37db7d5fbf3a35 Reviewed-on: https://go-review.googlesource.com/22322 Run-TryBot: David Crawshaw Reviewed-by: Brad Fitzpatrick --- src/cmd/link/internal/ppc64/asm.go | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go index 562e0810e0..17ee25608b 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,11 @@ 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 + 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 := *pprevtextp; s != nil; pprevtextp, s = &s.Next, s.Next { + for i := range s.R { + r := &s.R[i] if r.Type != 256+ld.R_PPC64_REL24 || r.Sym.Type != obj.SDYNIMPORT { continue } @@ -109,9 +101,9 @@ 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 } @@ -135,7 +127,7 @@ 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) } } -- cgit v1.3-5-g9baa From cda0aa16807b20410e57992b09570f6a9dd11f9b Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Wed, 20 Apr 2016 10:36:49 -0400 Subject: cmd/link: cleanup Datablk debug printing (Split out from CL 22205.) Change-Id: I45838dda8ea8c451b4388b8aade2c209cde2c0e1 Reviewed-on: https://go-review.googlesource.com/22299 Reviewed-by: Michael Hudson-Doyle Run-TryBot: Michael Hudson-Doyle TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/data.go | 69 +++++++++++++++------------------------- 1 file changed, 26 insertions(+), 43 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 8e2cf99877..b89644f229 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -665,11 +665,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 } @@ -704,9 +702,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) @@ -748,7 +745,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 @@ -766,8 +762,7 @@ 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)) @@ -874,12 +869,6 @@ func Datblk(addr int64, size int64) { } 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 { if sym.Value >= eaddr { break @@ -889,15 +878,12 @@ func Datblk(addr int64, size int64) { 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) && (-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)) @@ -906,27 +892,24 @@ func Datblk(addr int64, size int64) { } 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" - - 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 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) } } -- cgit v1.3-5-g9baa From ed41054b6d1306537df0ba3a34d11579ae2c1829 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Mon, 18 Apr 2016 14:50:14 -0400 Subject: cmd/link: process data symbols with slices First (and largest single) step to switching cmd/link from linked lists of symbols to slices. Sort sections independently and concurrently. This reduces jujud link times on linux/amd64 by ~4%. Updates #15374 Change-Id: I452bc8f33081039468636502fe3c1cc8d6ed9efa Reviewed-on: https://go-review.googlesource.com/22205 Reviewed-by: Michael Hudson-Doyle --- src/cmd/link/internal/ld/data.go | 626 ++++++++++++++++++++++---------------- src/cmd/link/internal/ld/elf.go | 17 +- src/cmd/link/internal/ld/lib.go | 3 +- src/cmd/link/internal/ld/macho.go | 16 +- src/cmd/link/internal/ld/pe.go | 14 +- 5 files changed, 380 insertions(+), 296 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index b89644f229..cc509fbc6d 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -32,7 +32,6 @@ package ld import ( - "bytes" "cmd/internal/gcprog" "cmd/internal/obj" "cmd/internal/sys" @@ -42,6 +41,7 @@ import ( "sort" "strconv" "strings" + "sync" ) func Symgrow(ctxt *Link, s *LSym, siz int64) { @@ -651,8 +651,8 @@ func reloc() { for s := Ctxt.Textp; s != nil; s = s.Next { relocsym(s) } - for s := datap; s != nil; s = s.Next { - relocsym(s) + for _, sym := range datap { + relocsym(sym) } for s := dwarfp; s != nil; s = s.Next { relocsym(s) @@ -713,7 +713,7 @@ 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 { @@ -727,8 +727,10 @@ func dynreloc() { for s := Ctxt.Textp; s != nil; s = s.Next { 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() @@ -849,27 +851,77 @@ func Codeblk(addr int64, size int64) { 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()) } - 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 - for ; sym != nil; sym = sym.Next { + for _, sym := range syms { if sym.Value >= eaddr { break } @@ -1080,18 +1132,15 @@ func aligndatsize(datsize int64, s *LSym) int64 { } // 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) +// the slice of symbols syms +func maxalign(syms []*LSym) int32 { + var max int32 + for _, sym := range syms { + align := symalign(sym) if max < align { max = align } } - return max } @@ -1156,41 +1205,24 @@ 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 - } - - // 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 - } +type bySizeAndName []dataSortKey - // Sort typelinks by the string field. - if strings.HasPrefix(s1.Name, "go.typelink.") && strings.HasPrefix(s2.Name, "go.typelink.") { - s1n := decodetype_string(s1.Lsym.R[0].Sym) - s2n := decodetype_string(s2.Lsym.R[0].Sym) - return bytes.Compare(s1n, s2n) < 0 +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) { @@ -1207,38 +1239,17 @@ func growdatsize(datsizep *int64, s *LSym) { *datsizep = datsize + s.Size } -func list2Slice(head *LSym) dataSlice { - n := 0 - for s := datap; s != nil; s = s.Next { - n++ - } - 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 { @@ -1246,153 +1257,122 @@ func dodata() { } 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, 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 + for symnro := int16(obj.STYPE); symnro < obj.STYPERELRO; symnro++ { + symnrelro := symnro + obj.STYPERELRO - obj.STYPE + + ro := []*LSym{} + relro := data[symnrelro] + + 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) } } - } - // 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) - } - } - - } - datap = dataSort(datap) - - 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 - } - } - 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 wg sync.WaitGroup + for symn := range data { + symn := symn + wg.Add(1) + go func() { + data[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) + growdatsize(&datsize, s) + sect.Length = uint64(datsize) - sect.Vaddr + } } - /* .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 = maxalign(data[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 @@ -1400,7 +1380,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 @@ -1412,26 +1391,24 @@ func dodata() { growdatsize(&datsize, s) } - sect.Length = uint64(datsize) - sect.Vaddr } /* pointer-free data */ - sect = addsection(&Segdata, ".noptrdata", 06) + sect := addsection(&Segdata, ".noptrdata", 06) - sect.Align = maxalign(s, obj.SINITARR-1) + sect.Align = maxalign(data[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) } - sect.Length = uint64(datsize) - sect.Vaddr hasinitarr := Linkshared @@ -1441,37 +1418,30 @@ func dodata() { case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared: hasinitarr = true } - if hasinitarr { sect := addsection(&Segdata, ".init_array", 06) - sect.Align = maxalign(s, obj.SINITARR) + sect.Align = maxalign(data[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) } - sect.Length = uint64(datsize) - sect.Vaddr } /* data */ sect = addsection(&Segdata, ".data", 06) - sect.Align = maxalign(s, obj.SBSS-1) + sect.Align = maxalign(data[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) @@ -1484,14 +1454,14 @@ func dodata() { /* bss */ sect = addsection(&Segdata, ".bss", 06) - sect.Align = maxalign(s, obj.SNOPTRBSS-1) + sect.Align = maxalign(data[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) @@ -1504,12 +1474,12 @@ func dodata() { /* pointer-free bss */ sect = addsection(&Segdata, ".noptrbss", 06) - sect.Align = maxalign(s, obj.SNOPTRBSS) + sect.Align = maxalign(data[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) @@ -1519,22 +1489,21 @@ func dodata() { sect.Length = uint64(datsize) - sect.Vaddr Linklookup(Ctxt, "runtime.end", 0).Sect = sect - // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. + // The compiler 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(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 @@ -1546,11 +1515,6 @@ func dodata() { } } - 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. @@ -1568,13 +1532,14 @@ 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) @@ -1588,8 +1553,6 @@ func dodata() { /* 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 @@ -1597,14 +1560,32 @@ func dodata() { Linklookup(Ctxt, "runtime.types", 0).Sect = sect Linklookup(Ctxt, "runtime.etypes", 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) + roSects := []int{ + obj.STYPE, + obj.SSTRING, + obj.SGOSTRING, + obj.SGOSTRINGHDR, + obj.SGOFUNC, + obj.SGCBITS, + obj.SRODATA, + obj.SFUNCTAB, + } + for _, symn := range roSects { + align := maxalign(data[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) + growdatsize(&datsize, s) + } } - sect.Length = uint64(datsize) - sect.Vaddr // There is some data that are conceptually read-only but are written to by @@ -1626,20 +1607,37 @@ 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 Linklookup(Ctxt, "runtime.types", 0).Sect = sect Linklookup(Ctxt, "runtime.etypes", 0).Sect = sect - 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) + relroSects := []int{ + obj.STYPERELRO, + obj.SSTRINGRELRO, + obj.SGOSTRINGRELRO, + obj.SGOSTRINGHDRRELRO, + obj.SGOFUNCRELRO, + obj.SGCBITSRELRO, + obj.SRODATARELRO, + obj.SFUNCTABRELRO, + } + for _, symn := range relroSects { + align := maxalign(data[symn]) + if sect.Align < align { + sect.Align = align + } + } + 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) + growdatsize(&datsize, s) } - s.Sect = sect - s.Type = obj.SRODATA - s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) } sect.Length = uint64(datsize) - sect.Vaddr @@ -1648,78 +1646,85 @@ func dodata() { /* typelink */ sect = addsection(segro, relro_prefix+".typelink", relro_perms) - - sect.Align = maxalign(s, obj.STYPELINK) + sect.Align = maxalign(data[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) } - sect.Length = uint64(datsize) - sect.Vaddr /* itablink */ sect = addsection(segro, relro_prefix+".itablink", relro_perms) - sect.Align = maxalign(s, obj.SITABLINK) + sect.Align = maxalign(data[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) } - sect.Length = uint64(datsize) - sect.Vaddr /* gosymtab */ sect = addsection(segro, relro_prefix+".gosymtab", relro_perms) - sect.Align = maxalign(s, obj.SPCLNTAB-1) + sect.Align = maxalign(data[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) } - sect.Length = uint64(datsize) - sect.Vaddr /* gopclntab */ sect = addsection(segro, relro_prefix+".gopclntab", relro_perms) - sect.Align = maxalign(s, obj.SELFROSECT-1) + sect.Align = maxalign(data[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) } - 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)) + sect.Vaddr = uint64(datsize) + s.Sect = sect + s.Type = obj.SRODATA + s.Value = int64(uint64(datsize) - sect.Vaddr) + growdatsize(&datsize, s) + sect.Length = uint64(datsize) - sect.Vaddr + } + + for _, s := range data[obj.SMACHOPLT] { sect = addsection(segro, s.Name, 04) sect.Align = symalign(s) datsize = Rnd(datsize, int64(sect.Align)) @@ -1736,8 +1741,13 @@ func dodata() { 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 @@ -1791,6 +1801,84 @@ func dodata() { } } +func dodataSect(symn int, syms []*LSym) []*LSym { + 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 + if int64(len(s.P)) > s.Size { + Diag("%s: initialize bounds (%d < %d)", s.Name, s.Size, len(s.P)) + } + + 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_string(s.R[0].Sym)) + } + } + + sort.Sort(bySizeAndName(symsSort)) + + for i, symSort := range symsSort { + syms[i] = symSort.lsym + } + + 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 { + newSyms := make([]*LSym, 0, len(syms)) + plt := syms[plti] + newSyms = append(newSyms, syms[:reli+1]...) + newSyms = append(newSyms, plt) + newSyms = append(newSyms, syms[reli+1:plti]...) + newSyms = append(newSyms, syms[plti+1:]...) + if len(newSyms) != len(syms) { + Diag("plt move failed: len %d/%d", len(newSyms), len(syms)) + } + syms = newSyms + } + } + + return syms +} + // Add buildid to beginning of text segment, on non-ELF systems. // Non-ELF binary formats are not always flexible enough to // give us a place to put the Go build ID. On those systems, we put it @@ -1816,8 +1904,6 @@ func textbuildid() { // assign addresses to text func textaddress() { - var sub *LSym - addsection(&Segtext, ".text", 05) // Assign PCs in text segment. @@ -1844,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 { @@ -1982,22 +2068,22 @@ func address() { symtab := itablink.Next pclntab := symtab.Next - var sub *LSym - for sym := datap; sym != nil; sym = sym.Next { - Ctxt.Cursym = sym - if sym.Sect != nil { - sym.Value += int64(sym.Sect.Vaddr) + for _, s := range datap { + Ctxt.Cursym = s + if s.Sect != nil { + s.Value += int64(s.Sect.Vaddr) } - for sub = sym.Sub; sub != nil; sub = sub.Sub { - sub.Value += sym.Value + 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 } } diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 15f0656aea..84aa58e7c7 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -1670,7 +1670,7 @@ func elfshreloc(sect *Section) *ElfShdr { 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 { @@ -1681,18 +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) - for ; sym != nil; sym = sym.Next { + for _, sym := range syms { if !sym.Attr.Reachable() { continue } @@ -1710,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) } @@ -1728,7 +1727,7 @@ func Elfemitreloc() { Cput(0) } - elfrelocsect(Segtext.Sect, Ctxt.Textp) + elfrelocsect(Segtext.Sect, list2slice(Ctxt.Textp)) for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next { elfrelocsect(sect, datap) } @@ -1739,7 +1738,7 @@ func Elfemitreloc() { elfrelocsect(sect, datap) } for sect := Segdwarf.Sect; sect != nil; sect = sect.Next { - elfrelocsect(sect, dwarfp) + elfrelocsect(sect, list2slice(dwarfp)) } } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 24cdca5a3b..d728dda5b6 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -130,7 +130,6 @@ func (r *Rpath) String() string { var ( Thearch Arch - datap *LSym Debug [128]int Lcsize int32 rpath Rpath @@ -2109,7 +2108,7 @@ func undef() { for s := Ctxt.Textp; s != nil; s = s.Next { undefsym(s) } - for s := datap; s != nil; s = s.Next { + for _, s := range datap { undefsym(s) } if nerrors > 0 { diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index 6ca5ba5861..5b2906ee27 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -806,25 +806,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) - for ; sym != nil; sym = sym.Next { + for _, sym := range syms { if !sym.Attr.Reachable() { continue } @@ -852,7 +852,7 @@ func Machoemitreloc() { Cput(0) } - machorelocsect(Segtext.Sect, Ctxt.Textp) + machorelocsect(Segtext.Sect, list2slice(Ctxt.Textp)) for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next { machorelocsect(sect, datap) } @@ -860,6 +860,6 @@ func Machoemitreloc() { machorelocsect(sect, datap) } for sect := Segdwarf.Sect; sect != nil; sect = sect.Next { - machorelocsect(sect, dwarfp) + machorelocsect(sect, list2slice(dwarfp)) } } diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index 3b477fd846..c0df07d359 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -764,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 @@ -773,18 +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) - for ; sym != nil; sym = sym.Next { + for _, sym := range syms { if !sym.Attr.Reachable() { continue } @@ -831,7 +831,7 @@ func peemitreloc(text, data, ctors *IMAGE_SECTION_HEADER) { Lputl(0) Wputl(0) - n := perelocsect(Segtext.Sect, Ctxt.Textp) + 1 + n := perelocsect(Segtext.Sect, list2slice(Ctxt.Textp)) + 1 for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next { n += perelocsect(sect, datap) } -- cgit v1.3-5-g9baa From 9568d54fb8d89267304d23cac23190f55ec95683 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Wed, 20 Apr 2016 19:10:20 -0400 Subject: cmd/link: fix reordering of plt/rel For the Solaris and S/390 builders. Change-Id: Id9a83e0df91e6d0df8488ec5e2a546ba8e2d800e Reviewed-on: https://go-review.googlesource.com/22327 Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot Reviewed-by: Michael Hudson-Doyle Reviewed-by: Michael Munday --- src/cmd/link/internal/ld/data.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index cc509fbc6d..e73fa041a4 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -1863,16 +1863,16 @@ func dodataSect(symn int, syms []*LSym) []*LSym { } } if reli >= 0 && plti >= 0 && plti != reli+1 { - newSyms := make([]*LSym, 0, len(syms)) - plt := syms[plti] - newSyms = append(newSyms, syms[:reli+1]...) - newSyms = append(newSyms, plt) - newSyms = append(newSyms, syms[reli+1:plti]...) - newSyms = append(newSyms, syms[plti+1:]...) - if len(newSyms) != len(syms) { - Diag("plt move failed: len %d/%d", len(newSyms), len(syms)) + var first, second int + if plti > reli { + first, second = reli, plti + } else { + first, second = plti, reli } - syms = newSyms + rel, plt := syms[reli], syms[plti] + copy(syms[first+2:], syms[first+1:second]) + syms[first+0] = rel + syms[first+1] = plt } } -- cgit v1.3-5-g9baa From 5a0881a1d1797a5f34c33ec4cf67cb97cc1aa634 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Tue, 19 Apr 2016 08:59:56 -0400 Subject: cmd/link: calculate section alignment concurrently Reduces link time for cmd/go by 1%. Change-Id: Iad4a16db0aedc56f81ddf73ba9b632e418dc1b19 Reviewed-on: https://go-review.googlesource.com/22242 Reviewed-by: Michael Hudson-Doyle Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/data.go | 145 +++++++++++++++++++-------------------- 1 file changed, 70 insertions(+), 75 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index e73fa041a4..71af0e4730 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -1131,19 +1131,6 @@ func aligndatsize(datsize int64, s *LSym) int64 { return Rnd(datsize, int64(symalign(s))) } -// maxalign returns the maximum required alignment for -// the slice of symbols syms -func maxalign(syms []*LSym) int32 { - var max int32 - for _, sym := range syms { - align := symalign(sym) - if max < align { - max = align - } - } - return max -} - const debugGCProg = false type GCProg struct { @@ -1225,18 +1212,12 @@ func (d bySizeAndName) Less(i, j int) bool { 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 checkdatsize(datsize int64, symn int) { + if datsize > cutoff { + Diag("too much data in section %v (over %d bytes)", symn, cutoff) + } } func list2slice(s *LSym) []*LSym { @@ -1327,12 +1308,13 @@ func dodata() { } // Sort symbols. + var dataMaxAlign [obj.SXREF]int32 var wg sync.WaitGroup for symn := range data { symn := symn wg.Add(1) go func() { - data[symn] = dodataSect(symn, data[symn]) + data[symn], dataMaxAlign[symn] = dodataSect(symn, data[symn]) wg.Done() }() } @@ -1360,15 +1342,16 @@ func dodata() { s.Sect = sect s.Type = obj.SDATA s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) + datsize += s.Size sect.Length = uint64(datsize) - sect.Vaddr } + checkdatsize(datsize, symn) } // .got (and .toc on ppc64) if len(data[obj.SELFGOT]) > 0 { sect := addsection(&Segdata, ".got", 06) - sect.Align = maxalign(data[obj.SELFGOT]) + sect.Align = dataMaxAlign[obj.SELFGOT] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) var toc *LSym @@ -1389,15 +1372,15 @@ 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(data[obj.SNOPTRDATA]) + sect.Align = dataMaxAlign[obj.SNOPTRDATA] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.noptrdata", 0).Sect = sect @@ -1407,8 +1390,9 @@ func dodata() { 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 @@ -1420,21 +1404,22 @@ func dodata() { } if hasinitarr { sect := addsection(&Segdata, ".init_array", 06) - sect.Align = maxalign(data[obj.SINITARR]) + sect.Align = dataMaxAlign[obj.SINITARR] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) 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(data[obj.SDATA]) + sect.Align = dataMaxAlign[obj.SDATA] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.data", 0).Sect = sect @@ -1447,14 +1432,15 @@ func dodata() { 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(data[obj.SBSS]) + sect.Align = dataMaxAlign[obj.SBSS] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.bss", 0).Sect = sect @@ -1466,15 +1452,15 @@ func dodata() { 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(data[obj.SNOPTRBSS]) + sect.Align = dataMaxAlign[obj.SNOPTRBSS] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.noptrbss", 0).Sect = sect @@ -1483,16 +1469,12 @@ func dodata() { 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 - - // The compiler 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") - } + checkdatsize(datsize, obj.SNOPTRBSS) if len(data[obj.STLSBSS]) > 0 { var sect *Section @@ -1507,8 +1489,9 @@ func dodata() { 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) @@ -1546,8 +1529,9 @@ 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.SELFRXSECT) } /* read-only data */ @@ -1571,7 +1555,7 @@ func dodata() { obj.SFUNCTAB, } for _, symn := range roSects { - align := maxalign(data[symn]) + align := dataMaxAlign[symn] if sect.Align < align { sect.Align = align } @@ -1583,8 +1567,9 @@ func dodata() { s.Sect = sect s.Type = obj.SRODATA s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) + datsize += s.Size } + checkdatsize(datsize, symn) } sect.Length = uint64(datsize) - sect.Vaddr @@ -1621,7 +1606,7 @@ func dodata() { obj.SFUNCTABRELRO, } for _, symn := range relroSects { - align := maxalign(data[symn]) + align := dataMaxAlign[symn] if sect.Align < align { sect.Align = align } @@ -1636,8 +1621,9 @@ func dodata() { s.Sect = sect s.Type = obj.SRODATA s.Value = int64(uint64(datsize) - sect.Vaddr) - growdatsize(&datsize, s) + datsize += s.Size } + checkdatsize(datsize, symn) } sect.Length = uint64(datsize) - sect.Vaddr @@ -1646,7 +1632,7 @@ func dodata() { /* typelink */ sect = addsection(segro, relro_prefix+".typelink", relro_perms) - sect.Align = maxalign(data[obj.STYPELINK]) + sect.Align = dataMaxAlign[obj.STYPELINK] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.typelink", 0).Sect = sect @@ -1656,14 +1642,14 @@ func dodata() { 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(data[obj.SITABLINK]) + sect.Align = dataMaxAlign[obj.SITABLINK] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.itablink", 0).Sect = sect @@ -1673,14 +1659,14 @@ func dodata() { 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(data[obj.SSYMTAB]) + sect.Align = dataMaxAlign[obj.SSYMTAB] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.symtab", 0).Sect = sect @@ -1690,14 +1676,14 @@ func dodata() { 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(data[obj.SPCLNTAB]) + sect.Align = dataMaxAlign[obj.SPCLNTAB] datsize = Rnd(datsize, int64(sect.Align)) sect.Vaddr = uint64(datsize) Linklookup(Ctxt, "runtime.pclntab", 0).Sect = sect @@ -1707,8 +1693,9 @@ func dodata() { 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 */ @@ -1720,9 +1707,10 @@ 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) @@ -1732,9 +1720,10 @@ 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.SMACHOPLT) // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. if datsize != int64(uint32(datsize)) { @@ -1756,9 +1745,10 @@ 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.SDWARFSECT) if s != nil { sect = addsection(&Segdwarf, ".debug_info", 04) @@ -1770,14 +1760,10 @@ func dodata() { s.Type = obj.SRODATA s.Value = int64(uint64(datsize) - sect.Vaddr) s.Attr |= AttrLocal - growdatsize(&datsize, s) + datsize += s.Size } sect.Length = uint64(datsize) - sect.Vaddr - } - - // The compiler uses 4-byte relocation offsets, so the entire segment must fit in 32 bits. - if datsize != int64(uint32(datsize)) { - Diag("dwarf segment too large") + checkdatsize(datsize, obj.SDWARFINFO) } /* number the sections */ @@ -1801,7 +1787,7 @@ func dodata() { } } -func dodataSect(symn int, syms []*LSym) []*LSym { +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. @@ -1820,8 +1806,13 @@ func dodataSect(symn int, syms []*LSym) []*LSym { log.Fatalf("symbol %s listed multiple times", s.Name) } s.Attr |= AttrOnList - if int64(len(s.P)) > s.Size { + 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{ @@ -1848,6 +1839,10 @@ func dodataSect(symn int, syms []*LSym) []*LSym { for i, symSort := range symsSort { syms[i] = symSort.lsym + align := symalign(symSort.lsym) + if maxAlign < align { + maxAlign = align + } } if Iself && symn == obj.SELFROSECT { @@ -1876,7 +1871,7 @@ func dodataSect(symn int, syms []*LSym) []*LSym { } } - return syms + return syms, maxAlign } // Add buildid to beginning of text segment, on non-ELF systems. -- cgit v1.3-5-g9baa From 7d56215bcbc5a2ef5e59805271b0ca6a4fd56e4d Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Tue, 19 Apr 2016 14:02:21 -0400 Subject: cmd/link: convert textp into a slice Updates #15374 Change-Id: I3ea715735862fe9550b88d7a29def6cb9d4419a6 Reviewed-on: https://go-review.googlesource.com/22243 Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot Reviewed-by: Michael Hudson-Doyle --- src/cmd/link/internal/amd64/asm.go | 7 +----- src/cmd/link/internal/arm/asm.go | 7 +----- src/cmd/link/internal/arm64/asm.go | 7 +----- src/cmd/link/internal/ld/data.go | 15 +++++------ src/cmd/link/internal/ld/deadcode.go | 22 ++++------------ src/cmd/link/internal/ld/dwarf.go | 8 +++--- src/cmd/link/internal/ld/elf.go | 2 +- src/cmd/link/internal/ld/ldelf.go | 10 ++------ src/cmd/link/internal/ld/ldmacho.go | 10 ++------ src/cmd/link/internal/ld/ldpe.go | 10 ++------ src/cmd/link/internal/ld/lib.go | 38 ++++++++-------------------- src/cmd/link/internal/ld/link.go | 3 +-- src/cmd/link/internal/ld/macho.go | 2 +- src/cmd/link/internal/ld/objfile.go | 7 +----- src/cmd/link/internal/ld/pcln.go | 49 +++++++++++++++++------------------- src/cmd/link/internal/ld/pe.go | 2 +- src/cmd/link/internal/ppc64/asm.go | 23 +++-------------- src/cmd/link/internal/s390x/asm.go | 7 +----- src/cmd/link/internal/x86/asm.go | 10 ++------ 19 files changed, 71 insertions(+), 168 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index ab96a59151..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 diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go index 69e1d8f317..069812fcef 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 diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index d8ffffa157..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 diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 71af0e4730..8d20096dcf 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -648,7 +648,7 @@ func reloc() { } Bso.Flush() - for s := Ctxt.Textp; s != nil; s = s.Next { + for _, s := range Ctxt.Textp { relocsym(s) } for _, sym := range datap { @@ -724,7 +724,7 @@ func dynreloc(data *[obj.SXREF][]*LSym) { } Bso.Flush() - for s := Ctxt.Textp; s != nil; s = s.Next { + for _, s := range Ctxt.Textp { dynrelocsym(s) } for _, syms := range data { @@ -791,7 +791,7 @@ func Codeblk(addr int64, size int64) { 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 { @@ -799,7 +799,7 @@ func Codeblk(addr int64, size int64) { } var sym *LSym - for sym = Ctxt.Textp; sym != nil; sym = sym.Next { + for _, sym = range Ctxt.Textp { if !sym.Attr.Reachable() { continue } @@ -1893,8 +1893,9 @@ 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 @@ -1914,7 +1915,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 diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index c83a104a54..6a70ff581f 100644 --- a/src/cmd/link/internal/ld/deadcode.go +++ b/src/cmd/link/internal/ld/deadcode.go @@ -119,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{ diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index bec9946ec5..a5e26b49f2 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -1432,7 +1432,7 @@ func writelines(prev *LSym) *LSym { lang := DW_LANG_Go - s := Ctxt.Textp + s := Ctxt.Textp[0] dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, "go", 0) newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT, int64(lang), 0) @@ -1502,8 +1502,8 @@ func writelines(prev *LSym) *LSym { 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, int(s.Version)) newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s.Value, s) @@ -1696,7 +1696,7 @@ func writeframes(prev *LSym) *LSym { 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.FuncInfo == nil { continue diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 84aa58e7c7..15b8d7af93 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -1727,7 +1727,7 @@ func Elfemitreloc() { Cput(0) } - elfrelocsect(Segtext.Sect, list2slice(Ctxt.Textp)) + elfrelocsect(Segtext.Sect, Ctxt.Textp) for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next { elfrelocsect(sect, datap) } diff --git a/src/cmd/link/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go index 59e71f4dd4..af60a5c85b 100644 --- a/src/cmd/link/internal/ld/ldelf.go +++ b/src/cmd/link/internal/ld/ldelf.go @@ -842,19 +842,13 @@ func ldelf(f *bio.Reader, 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) } } } diff --git a/src/cmd/link/internal/ld/ldmacho.go b/src/cmd/link/internal/ld/ldmacho.go index 105fc137f9..a10124907c 100644 --- a/src/cmd/link/internal/ld/ldmacho.go +++ b/src/cmd/link/internal/ld/ldmacho.go @@ -707,19 +707,13 @@ func ldmacho(f *bio.Reader, 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) } } } diff --git a/src/cmd/link/internal/ld/ldpe.go b/src/cmd/link/internal/ld/ldpe.go index c51479fb4e..7eb26bcbe8 100644 --- a/src/cmd/link/internal/ld/ldpe.go +++ b/src/cmd/link/internal/ld/ldpe.go @@ -435,19 +435,13 @@ func ldpe(f *bio.Reader, 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) } } } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index d728dda5b6..77db672bfd 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1545,30 +1545,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}) } @@ -1682,7 +1666,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. @@ -1697,7 +1681,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 @@ -1995,7 +1979,7 @@ 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) @@ -2105,7 +2089,7 @@ func undefsym(s *LSym) { } func undef() { - for s := Ctxt.Textp; s != nil; s = s.Next { + for _, s := range Ctxt.Textp { undefsym(s) } for _, s := range datap { @@ -2123,7 +2107,7 @@ 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 { diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index b0bca4300f..a3b8e57ee5 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -178,8 +178,7 @@ type Link struct { Diag func(string, ...interface{}) Cursym *LSym Version int - Textp *LSym - Etextp *LSym + Textp []*LSym Nhistfile int32 Filesyms *LSym Moduledata *LSym diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index 5b2906ee27..310435e49e 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -852,7 +852,7 @@ func Machoemitreloc() { Cput(0) } - machorelocsect(Segtext.Sect, list2slice(Ctxt.Textp)) + machorelocsect(Segtext.Sect, Ctxt.Textp) for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next { machorelocsect(sect, datap) } diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go index 566c949040..bcfe52585f 100644 --- a/src/cmd/link/internal/ld/objfile.go +++ b/src/cmd/link/internal/ld/objfile.go @@ -398,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) } } } diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index e1c1d2d318..7d1858c95e 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -224,14 +224,14 @@ 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++ } } @@ -246,7 +246,7 @@ func pclntab() { nfunc = 0 var last *LSym - 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 @@ -401,10 +401,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 } @@ -417,34 +416,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 } @@ -457,15 +456,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 c0df07d359..839aa6cca7 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -831,7 +831,7 @@ func peemitreloc(text, data, ctors *IMAGE_SECTION_HEADER) { Lputl(0) Wputl(0) - n := perelocsect(Segtext.Sect, list2slice(Ctxt.Textp)) + 1 + n := perelocsect(Segtext.Sect, Ctxt.Textp) + 1 for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next { n += perelocsect(sect, datap) } diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go index 17ee25608b..dbf5fac0de 100644 --- a/src/cmd/link/internal/ppc64/asm.go +++ b/src/cmd/link/internal/ppc64/asm.go @@ -87,9 +87,7 @@ 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 _, 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 { @@ -110,15 +108,7 @@ func genplt() { 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) } @@ -131,7 +121,6 @@ func genplt() { ld.Ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off+4:], o1) } } - } func genaddmoduledata() { @@ -187,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 diff --git a/src/cmd/link/internal/s390x/asm.go b/src/cmd/link/internal/s390x/asm.go index 30b1e5a3e1..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 diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go index 5231ad1f6c..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 -- cgit v1.3-5-g9baa From 4b175fd23b3bf220e4121ba4986f2d7af1415482 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Fri, 22 Apr 2016 09:38:41 +1200 Subject: cmd/link: fix Codeblk printing when -a to use Textp as a slice Does anyone actually pass -a to the linker? Change-Id: I1d31ea66aa5604b7fd42adf15bdab71e9f52d0ed Reviewed-on: https://go-review.googlesource.com/22356 Run-TryBot: Michael Hudson-Doyle TryBot-Result: Gobot Gobot Reviewed-by: David Crawshaw --- src/cmd/link/internal/ld/data.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 8d20096dcf..6fc6de3818 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -798,19 +798,20 @@ func Codeblk(addr int64, size int64) { return } - var sym *LSym - for _, sym = range Ctxt.Textp { + 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 } -- cgit v1.3-5-g9baa From 25d95ee918b4b1315cb2fee0fc625d24cd408240 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Fri, 22 Apr 2016 10:10:08 +1200 Subject: cmd/link: convert Link.Filesyms into a slice Change-Id: I6490de325b0f4ba962c679503102d30d41dcc384 Reviewed-on: https://go-review.googlesource.com/22359 Run-TryBot: Michael Hudson-Doyle Reviewed-by: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/dwarf.go | 10 ++-------- src/cmd/link/internal/ld/link.go | 3 +-- src/cmd/link/internal/ld/pcln.go | 17 ++++++++--------- src/cmd/link/internal/ld/symtab.go | 4 ++-- 4 files changed, 13 insertions(+), 21 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index a5e26b49f2..0202df664a 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -1469,14 +1469,8 @@ func writelines(prev *LSym) *LSym { Adduint8(Ctxt, ls, 1) // standard_opcode_lengths[9] Adduint8(Ctxt, ls, 0) // include_directories (empty) - files := make([]*LSym, Ctxt.Nhistfile) - - for f := Ctxt.Filesyms; f != nil; f = f.Next { - files[f.Value-1] = f - } - - for i := 0; int32(i) < Ctxt.Nhistfile; i++ { - Addstring(ls, files[i].Name) + for _, f := range Ctxt.Filesyms { + Addstring(ls, f.Name) Adduint8(Ctxt, ls, 0) Adduint8(Ctxt, ls, 0) Adduint8(Ctxt, ls, 0) diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index a3b8e57ee5..d0515d4617 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -179,8 +179,7 @@ type Link struct { Cursym *LSym Version int Textp []*LSym - Nhistfile int32 - Filesyms *LSym + Filesyms []*LSym Moduledata *LSym LSymBatch []LSym } diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index 7d1858c95e..991b9ef2cd 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -147,12 +147,10 @@ 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 } } @@ -302,8 +300,8 @@ func pclntab() { // 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() } } @@ -360,9 +358,10 @@ func pclntab() { pclntabFiletabOffset = 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))) } diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index 1f07a4eb77..acc238f698 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -499,8 +499,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 -- cgit v1.3-5-g9baa From bb52ceafea60dc4688b6c6b71f241752ce597db8 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Thu, 7 Apr 2016 20:07:09 -0400 Subject: cmd/link: do not align type name data Now that reflect.name objects contain an offset to pkgPath instead of a pointer, there is no need to align the symbol data. Removes approx. 10KB from the cmd/go binary. The effect becomes more important later as more type data is moved into name objects. For #6853 Change-Id: Idb507fdbdad04f16fc224378f82272cb5c236ab7 Reviewed-on: https://go-review.googlesource.com/21776 Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/cmd/link/internal/ld/data.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 6fc6de3818..63caf9cf79 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -1116,7 +1116,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 -- cgit v1.3-5-g9baa From 1492e7db059ea7903110b0725d5ced3134558e73 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Thu, 7 Apr 2016 16:29:16 -0400 Subject: cmd/compile, etc: use nameOff for rtype string linux/amd64: cmd/go: -8KB (basically nothing) linux/amd64 PIE: cmd/go: -191KB (1.6%) jujud: -1.5MB (1.9%) Updates #6853 Fixes #15064 Change-Id: I0adbb95685e28be92e8548741df0e11daa0a9b5f Reviewed-on: https://go-review.googlesource.com/21777 Reviewed-by: Ian Lance Taylor --- src/cmd/compile/internal/gc/reflect.go | 58 +++++++++------ src/cmd/link/internal/ld/data.go | 2 +- src/cmd/link/internal/ld/decodesym.go | 35 +++++---- src/reflect/all_test.go | 40 +++++++++- src/reflect/export_test.go | 8 +- src/reflect/type.go | 129 +++++++++++++++++---------------- src/runtime/alg.go | 8 +- src/runtime/error.go | 2 +- src/runtime/heapdump.go | 2 +- src/runtime/iface.go | 24 +++--- src/runtime/mbitmap.go | 10 +-- src/runtime/mfinal.go | 10 +-- src/runtime/mprof.go | 2 +- src/runtime/type.go | 46 ++++++++---- 14 files changed, 231 insertions(+), 145 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index ac36f912b6..1643c2ce4b 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -788,14 +788,21 @@ func typeptrdata(t *Type) int64 { } } -// tflag is documented in ../../../../reflect/type.go. -const tflagUncommon = 1 - -// commonType -// ../../../../runtime/type.go:/commonType +// 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 +) var dcommontype_algarray *Sym +// dcommontype dumps the contents of a reflect.rtype (runtime._type). func dcommontype(s *Sym, ot int, t *Type) int { if ot != 0 { Fatalf("dcommontype %d", ot) @@ -836,7 +843,8 @@ func dcommontype(s *Sym, ot int, t *Type) int { // kind uint8 // alg *typeAlg // gcdata *byte - // string *string + // str nameOff + // _ int32 // } ot = duintptr(s, ot, uint64(t.Width)) ot = duintptr(s, ot, uint64(ptrdata)) @@ -847,6 +855,26 @@ func dcommontype(s *Sym, ot int, t *Type) int { if uncommonSize(t) != 0 { tflag |= tflagUncommon } + + exported := false + p := Tconv(t, FmtLeft|FmtUnsigned) + // If we're writing out type T, + // we are very likely to write out type *T as well. + // Use the string "*T"[1:] for "T", so that the two + // share storage. This is a cheap way to reduce the + // amount of space taken up by reflect strings. + if !strings.HasPrefix(p, "*") { + p = "*" + p + tflag |= tflagExtraStar + if t.Sym != nil { + exported = exportname(t.Sym.Name) + } + } else { + if t.Elem() != nil && t.Elem().Sym != nil { + exported = exportname(t.Elem().Sym.Name) + } + } + ot = duint8(s, ot, tflag) // runtime (and common sense) expects alignment to be a power of two. @@ -882,21 +910,9 @@ func dcommontype(s *Sym, ot int, t *Type) int { } ot = dsymptr(s, ot, gcsym, 0) // gcdata - p := Tconv(t, FmtLeft|FmtUnsigned) - - // If we're writing out type T, - // we are very likely to write out type *T as well. - // Use the string "*T"[1:] for "T", so that the two - // share storage. This is a cheap way to reduce the - // amount of space taken up by reflect strings. - prefix := 0 - if !strings.HasPrefix(p, "*") { - p = "*" + p - prefix = 1 - } - _, symdata := stringsym(p) // string - ot = dsymptrLSym(Linksym(s), ot, symdata, prefix) - ot = duintxx(s, ot, uint64(len(p)-prefix), Widthint) + nsym := dname(p, "", nil, exported) + ot = dsymptrOffLSym(Linksym(s), ot, nsym, 0) + ot = duint32(s, ot, 0) return ot } diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 63caf9cf79..dbd5ad0b75 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -1832,7 +1832,7 @@ func dodataSect(symn int, syms []*LSym) (result []*LSym, maxAlign int32) { case obj.STYPELINK: // Sort typelinks by the rtype.string field so the reflect // package can binary search type links. - symsSort[i].name = string(decodetype_string(s.R[0].Sym)) + symsSort[i].name = string(decodetype_str(s.R[0].Sym)) } } diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index b1c55cf787..330aa6dc13 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -16,6 +16,18 @@ 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 := range s.R { if s.R[i].Off == off { @@ -47,9 +59,9 @@ func decode_inuxi(p []byte, sz int) uint64 { } } -func commonsize() int { return 6*SysArch.PtrSize + 8 } // runtime._type -func structfieldSize() int { return 3 * SysArch.PtrSize } // runtime.structfield -func uncommonSize() int { return 2 * SysArch.PtrSize } // 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 2 * SysArch.PtrSize } // runtime.uncommontype // Type.commonType.kind func decodetype_kind(s *LSym) uint8 { @@ -73,7 +85,6 @@ func decodetype_ptrdata(s *LSym) int64 { // Type.commonType.tflag func decodetype_hasUncommon(s *LSym) bool { - const tflagUncommon = 1 // see ../../../../reflect/type.go:/^type.tflag return s.P[2*SysArch.PtrSize+4]&tflagUncommon != 0 } @@ -211,16 +222,13 @@ func decodetype_structfieldarrayoff(s *LSym, i int) int { return off } -// decodetype_string returns the contents of an rtype's string field. -func decodetype_string(s *LSym) []byte { - off := 4*SysArch.PtrSize + 8 - strlen := int64(decode_inuxi(s.P[off+SysArch.PtrSize:], SysArch.IntSize)) - - r := decode_reloc(s, int32(off)) - if r == nil { - return nil +// 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:] } - return r.Sym.P[r.Add : r.Add+strlen] + return str } // decodetype_name decodes the name from a reflect.name. @@ -233,7 +241,6 @@ func decodetype_name(s *LSym, off int) string { data := r.Sym.P namelen := int(uint16(data[1]<<8) | uint16(data[2])) return string(data[3 : 3+namelen]) - } func decodetype_structfieldname(s *LSym, i int) string { diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 4dfae2743d..e88bc880e2 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -4175,12 +4175,12 @@ func TestStructOfExportRules(t *testing.T) { }, { field: StructField{Name: "", Type: TypeOf(ΦType{})}, - mustPanic: true, // TODO(sbinet): creating a struct with UTF-8 fields not supported + mustPanic: false, exported: true, }, { field: StructField{Name: "", Type: TypeOf(φType{})}, - mustPanic: true, // TODO(sbinet): creating a struct with UTF-8 fields not supported + mustPanic: false, exported: false, }, { @@ -5674,6 +5674,42 @@ func TestNames(t *testing.T) { } } +func TestExported(t *testing.T) { + type ΦExported struct{} + type φUnexported struct{} + type BigP *big + type P int + type p *P + type P2 p + type p3 p + + type exportTest struct { + v interface{} + want bool + } + exportTests := []exportTest{ + {D1{}, true}, + {(*D1)(nil), true}, + {big{}, false}, + {(*big)(nil), false}, + {(BigP)(nil), true}, + {(*BigP)(nil), true}, + {ΦExported{}, true}, + {φUnexported{}, false}, + {P(0), true}, + {(p)(nil), false}, + {(P2)(nil), true}, + {(p3)(nil), false}, + } + + for i, test := range exportTests { + typ := TypeOf(test.v) + if got := IsExported(typ); got != test.want { + t.Errorf("%d: %s exported=%v, want %v", i, typ.Name(), got, test.want) + } + } +} + type embed struct { EmbedWithUnexpMeth } diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go index f527434f0d..00189f3353 100644 --- a/src/reflect/export_test.go +++ b/src/reflect/export_test.go @@ -51,7 +51,7 @@ func TypeLinks() []string { rodata := sections[i] for _, off := range offs { typ := (*rtype)(resolveTypeOff(unsafe.Pointer(rodata), off)) - r = append(r, typ.string) + r = append(r, typ.String()) } } return r @@ -103,3 +103,9 @@ type OtherPkgFields struct { OtherExported int otherUnexported int } + +func IsExported(t Type) bool { + typ := t.(*rtype) + n := typ.nameOff(typ.str) + return n.isExported() +} diff --git a/src/reflect/type.go b/src/reflect/type.go index 0cae69a79c..b1758e6913 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -242,6 +242,11 @@ const ( // tflag is used by an rtype to signal what extra type information is // available in the memory directly following the rtype value. +// +// tflag values must be kept in sync with copies in: +// cmd/compile/internal/gc/reflect.go +// cmd/link/internal/ld/decodesym.go +// runtime/type.go type tflag uint8 const ( @@ -256,7 +261,13 @@ const ( // u uncommonType // } // u := &(*tUncommon)(unsafe.Pointer(t)).u - tflagUncommon tflag = 1 + tflagUncommon tflag = 1 << 0 + + // tflagExtraStar means the name in the str field has an + // extraneous '*' prefix. This is because for most types T in + // a program, the type *T also exists and reusing the str data + // saves binary size. + tflagExtraStar tflag = 1 << 1 ) // rtype is the common implementation of most values. @@ -273,7 +284,8 @@ type rtype struct { kind uint8 // enumeration for C alg *typeAlg // algorithm table gcdata *byte // garbage collection data - string string // string form; unnecessary but undeniably useful + str nameOff // string form + _ int32 // unused; keeps rtype always a multiple of ptrSize } // a copy of runtime.typeAlg @@ -420,6 +432,9 @@ type structType struct { // If the import path follows, then 4 bytes at the end of // the data form a nameOff. The import path is only set for concrete // methods that are defined in a different package than their type. +// +// If a name starts with "*", then the exported bit represents +// whether the pointed to type is exported. type name struct { bytes *byte } @@ -724,7 +739,13 @@ func (t *rtype) uncommon() *uncommonType { } } -func (t *rtype) String() string { return t.string } +func (t *rtype) String() string { + s := t.nameOff(t.str).name() + if t.tflag&tflagExtraStar != 0 { + return s[1:] + } + return s +} func (t *rtype) Size() uintptr { return t.size } @@ -833,33 +854,34 @@ func hasPrefix(s, prefix string) bool { } func (t *rtype) Name() string { - if hasPrefix(t.string, "map[") { + s := t.String() + if hasPrefix(s, "map[") { return "" } - if hasPrefix(t.string, "struct {") { + if hasPrefix(s, "struct {") { return "" } - if hasPrefix(t.string, "chan ") { + if hasPrefix(s, "chan ") { return "" } - if hasPrefix(t.string, "chan<-") { + if hasPrefix(s, "chan<-") { return "" } - if hasPrefix(t.string, "func(") { + if hasPrefix(s, "func(") { return "" } - switch t.string[0] { + switch s[0] { case '[', '*', '<': return "" } - i := len(t.string) - 1 + i := len(s) - 1 for i >= 0 { - if t.string[i] == '.' { + if s[i] == '.' { break } i-- } - return t.string[i+1:] + return s[i+1:] } func (t *rtype) ChanDir() ChanDir { @@ -1391,7 +1413,7 @@ func (t *rtype) ptrTo() *rtype { } // Look in known types. - s := "*" + t.string + s := "*" + t.String() for _, tt := range typesByString(s) { p = (*ptrType)(unsafe.Pointer(tt)) if p.elem == t { @@ -1408,7 +1430,7 @@ func (t *rtype) ptrTo() *rtype { prototype := *(**ptrType)(unsafe.Pointer(&iptr)) *p = *prototype - p.string = s + p.str = resolveReflectName(newName(s, "", "", false)) // For the type structures linked into the binary, the // compiler provides a good hash of the string. @@ -1645,7 +1667,7 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool { // // and // -// t1.string < t2.string +// t1.String() < t2.String() // // Note that strings are not unique identifiers for types: // there can be more than one with a given string. @@ -1669,12 +1691,12 @@ func typesByString(s string) []*rtype { section := sections[offsI] // We are looking for the first index i where the string becomes >= s. - // This is a copy of sort.Search, with f(h) replaced by (*typ[h].string >= s). + // This is a copy of sort.Search, with f(h) replaced by (*typ[h].String() >= s). i, j := 0, len(offs) for i < j { h := i + (j-i)/2 // avoid overflow when computing h // i ≤ h < j - if !(rtypeOff(section, offs[h]).string >= s) { + if !(rtypeOff(section, offs[h]).String() >= s) { i = h + 1 // preserves f(i-1) == false } else { j = h // preserves f(j) == true @@ -1687,7 +1709,7 @@ func typesByString(s string) []*rtype { // to do a linear scan anyway. for j := i; j < len(offs); j++ { typ := rtypeOff(section, offs[j]) - if typ.string != s { + if typ.String() != s { break } ret = append(ret, typ) @@ -1783,11 +1805,11 @@ func ChanOf(dir ChanDir, t Type) Type { lookupCache.Unlock() panic("reflect.ChanOf: invalid dir") case SendDir: - s = "chan<- " + typ.string + s = "chan<- " + typ.String() case RecvDir: - s = "<-chan " + typ.string + s = "<-chan " + typ.String() case BothDir: - s = "chan " + typ.string + s = "chan " + typ.String() } for _, tt := range typesByString(s) { ch := (*chanType)(unsafe.Pointer(tt)) @@ -1802,7 +1824,7 @@ func ChanOf(dir ChanDir, t Type) Type { ch := new(chanType) *ch = *prototype ch.dir = uintptr(dir) - ch.string = s + ch.str = resolveReflectName(newName(s, "", "", false)) ch.hash = fnv1(typ.hash, 'c', byte(dir)) ch.elem = typ @@ -1832,7 +1854,7 @@ func MapOf(key, elem Type) Type { } // Look in known types. - s := "map[" + ktyp.string + "]" + etyp.string + s := "map[" + ktyp.String() + "]" + etyp.String() for _, tt := range typesByString(s) { mt := (*mapType)(unsafe.Pointer(tt)) if mt.key == ktyp && mt.elem == etyp { @@ -1844,7 +1866,7 @@ func MapOf(key, elem Type) Type { var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil) mt := new(mapType) *mt = **(**mapType)(unsafe.Pointer(&imap)) - mt.string = s + mt.str = resolveReflectName(newName(s, "", "", false)) mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash)) mt.key = ktyp mt.elem = etyp @@ -2002,7 +2024,7 @@ func FuncOf(in, out []Type, variadic bool) Type { } // Populate the remaining fields of ft and store in cache. - ft.string = str + ft.str = resolveReflectName(newName(str, "", "", false)) funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype) return &ft.rtype @@ -2018,9 +2040,9 @@ func funcStr(ft *funcType) string { } if ft.IsVariadic() && i == int(ft.inCount)-1 { repr = append(repr, "..."...) - repr = append(repr, (*sliceType)(unsafe.Pointer(t)).elem.string...) + repr = append(repr, (*sliceType)(unsafe.Pointer(t)).elem.String()...) } else { - repr = append(repr, t.string...) + repr = append(repr, t.String()...) } } repr = append(repr, ')') @@ -2034,7 +2056,7 @@ func funcStr(ft *funcType) string { if i > 0 { repr = append(repr, ", "...) } - repr = append(repr, t.string...) + repr = append(repr, t.String()...) } if len(out) > 1 { repr = append(repr, ')') @@ -2199,8 +2221,8 @@ func bucketOf(ktyp, etyp *rtype) *rtype { b.ptrdata = ptrdata b.kind = kind b.gcdata = gcdata - s := "bucket(" + ktyp.string + "," + etyp.string + ")" - b.string = s + s := "bucket(" + ktyp.String() + "," + etyp.String() + ")" + b.str = resolveReflectName(newName(s, "", "", false)) return b } @@ -2216,7 +2238,7 @@ func SliceOf(t Type) Type { } // Look in known types. - s := "[]" + typ.string + s := "[]" + typ.String() for _, tt := range typesByString(s) { slice := (*sliceType)(unsafe.Pointer(tt)) if slice.elem == typ { @@ -2229,7 +2251,7 @@ func SliceOf(t Type) Type { prototype := *(**sliceType)(unsafe.Pointer(&islice)) slice := new(sliceType) *slice = *prototype - slice.string = s + slice.str = resolveReflectName(newName(s, "", "", false)) slice.hash = fnv1(typ.hash, '[') slice.elem = typ @@ -2337,11 +2359,11 @@ func StructOf(fields []StructField) Type { // Embedded ** and *interface{} are illegal elem := ft.Elem() if k := elem.Kind(); k == Ptr || k == Interface { - panic("reflect.StructOf: illegal anonymous field type " + ft.string) + panic("reflect.StructOf: illegal anonymous field type " + ft.String()) } name = elem.String() } else { - name = ft.string + name = ft.String() } // TODO(sbinet) check for syntactically impossible type names? @@ -2463,7 +2485,7 @@ func StructOf(fields []StructField) Type { hash = fnv1(hash, byte(ft.hash>>24), byte(ft.hash>>16), byte(ft.hash>>8), byte(ft.hash)) - repr = append(repr, (" " + ft.string)...) + repr = append(repr, (" " + ft.String())...) if f.name.tagLen() > 0 { hash = fnv1(hash, []byte(f.name.tag())...) repr = append(repr, (" " + strconv.Quote(f.name.tag()))...) @@ -2579,7 +2601,7 @@ func StructOf(fields []StructField) Type { } } - typ.string = str + typ.str = resolveReflectName(newName(str, "", "", false)) typ.hash = hash typ.size = size typ.align = typalign @@ -2691,11 +2713,11 @@ func StructOf(fields []StructField) Type { func runtimeStructField(field StructField) structField { exported := field.PkgPath == "" if field.Name == "" { - t := field.Type + t := field.Type.(*rtype) if t.Kind() == Ptr { - t = t.Elem() + t = t.Elem().(*rtype) } - exported = isExported(t.Name()) + exported = t.nameOff(t.str).isExported() } else if exported { b0 := field.Name[0] if ('a' <= b0 && b0 <= 'z') || b0 == '_' { @@ -2711,25 +2733,6 @@ func runtimeStructField(field StructField) structField { } } -func isExported(s string) bool { - if s == "" { - return false - } - // FIXME(sbinet): handle utf8/runes (see https://golang.org/issue/15064) - // TODO: turn rtype.string into a reflect.name type, and put the exported - // bit on there which can be checked here with field.Type.(*rtype).string.isExported() - // When done, remove the documented limitation of StructOf. - r := s[0] - switch { - case 'A' <= r && r <= 'Z': - return true - case r == '_' || 'a' <= r && r <= 'z': - return false - default: - panic("reflect.StructOf: creating a struct with UTF-8 fields is not supported yet") - } -} - // typeptrdata returns the length in bytes of the prefix of t // containing pointer data. Anything after this offset is scalar data. // keep in sync with ../cmd/compile/internal/gc/reflect.go @@ -2779,7 +2782,7 @@ func ArrayOf(count int, elem Type) Type { } // Look in known types. - s := "[" + strconv.Itoa(count) + "]" + typ.string + s := "[" + strconv.Itoa(count) + "]" + typ.String() for _, tt := range typesByString(s) { array := (*arrayType)(unsafe.Pointer(tt)) if array.elem == typ { @@ -2792,7 +2795,7 @@ func ArrayOf(count int, elem Type) Type { prototype := *(**arrayType)(unsafe.Pointer(&iarray)) array := new(arrayType) *array = *prototype - array.string = s + array.str = resolveReflectName(newName(s, "", "", false)) array.hash = fnv1(typ.hash, '[') for n := uint32(count); n > 0; n >>= 8 { array.hash = fnv1(array.hash, byte(n)) @@ -3046,11 +3049,11 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin var s string if rcvr != nil { - s = "methodargs(" + rcvr.string + ")(" + t.string + ")" + s = "methodargs(" + rcvr.String() + ")(" + t.String() + ")" } else { - s = "funcargs(" + t.string + ")" + s = "funcargs(" + t.String() + ")" } - x.string = s + x.str = resolveReflectName(newName(s, "", "", false)) // cache result for future callers if layoutCache.m == nil { diff --git a/src/runtime/alg.go b/src/runtime/alg.go index 7aacc8cf9b..66943495b5 100644 --- a/src/runtime/alg.go +++ b/src/runtime/alg.go @@ -146,7 +146,7 @@ func interhash(p unsafe.Pointer, h uintptr) uintptr { t := tab._type fn := t.alg.hash if fn == nil { - panic(errorString("hash of unhashable type " + t._string)) + panic(errorString("hash of unhashable type " + t.string())) } if isDirectIface(t) { return c1 * fn(unsafe.Pointer(&a.data), h^c0) @@ -163,7 +163,7 @@ func nilinterhash(p unsafe.Pointer, h uintptr) uintptr { } fn := t.alg.hash if fn == nil { - panic(errorString("hash of unhashable type " + t._string)) + panic(errorString("hash of unhashable type " + t.string())) } if isDirectIface(t) { return c1 * fn(unsafe.Pointer(&a.data), h^c0) @@ -221,7 +221,7 @@ func efaceeq(x, y eface) bool { } eq := t.alg.equal if eq == nil { - panic(errorString("comparing uncomparable type " + t._string)) + panic(errorString("comparing uncomparable type " + t.string())) } if isDirectIface(t) { return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data))) @@ -239,7 +239,7 @@ func ifaceeq(x, y iface) bool { t := xtab._type eq := t.alg.equal if eq == nil { - panic(errorString("comparing uncomparable type " + t._string)) + panic(errorString("comparing uncomparable type " + t.string())) } if isDirectIface(t) { return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data))) diff --git a/src/runtime/error.go b/src/runtime/error.go index 15f6bdf014..0238c5e592 100644 --- a/src/runtime/error.go +++ b/src/runtime/error.go @@ -67,7 +67,7 @@ type stringer interface { func typestring(x interface{}) string { e := efaceOf(&x) - return e._type._string + return e._type.string() } // For calling from C. diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index adfd660847..1db29d7cb4 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -184,7 +184,7 @@ func dumptype(t *_type) { dumpint(uint64(uintptr(unsafe.Pointer(t)))) dumpint(uint64(t.size)) if x := t.uncommon(); x == nil || x.pkgpath.name() == "" { - dumpstr(t._string) + dumpstr(t.string()) } else { pkgpathstr := x.pkgpath.name() pkgpath := stringStructOf(&pkgpathstr) diff --git a/src/runtime/iface.go b/src/runtime/iface.go index 352ff77465..007c1ed174 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -38,7 +38,7 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab { return nil } name := inter.typ.nameOff(inter.mhdr[0].name) - panic(&TypeAssertionError{"", typ._string, inter.typ._string, name.name()}) + panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), name.name()}) } h := itabhash(inter, typ) @@ -128,7 +128,7 @@ func additab(m *itab, locked, canfail bool) { if locked { unlock(&ifaceLock) } - panic(&TypeAssertionError{"", typ._string, inter.typ._string, iname}) + panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), iname}) } m.bad = 1 break @@ -196,18 +196,18 @@ func convT2I(tab *itab, elem unsafe.Pointer, x unsafe.Pointer) (i iface) { func panicdottype(have, want, iface *_type) { haveString := "" if have != nil { - haveString = have._string + haveString = have.string() } - panic(&TypeAssertionError{iface._string, haveString, want._string, ""}) + panic(&TypeAssertionError{iface.string(), haveString, want.string(), ""}) } func assertI2T(t *_type, i iface, r unsafe.Pointer) { tab := i.tab if tab == nil { - panic(&TypeAssertionError{"", "", t._string, ""}) + panic(&TypeAssertionError{"", "", t.string(), ""}) } if tab._type != t { - panic(&TypeAssertionError{tab.inter.typ._string, tab._type._string, t._string, ""}) + panic(&TypeAssertionError{tab.inter.typ.string(), tab._type.string(), t.string(), ""}) } if r != nil { if isDirectIface(t) { @@ -238,10 +238,10 @@ func assertI2T2(t *_type, i iface, r unsafe.Pointer) bool { func assertE2T(t *_type, e eface, r unsafe.Pointer) { if e._type == nil { - panic(&TypeAssertionError{"", "", t._string, ""}) + panic(&TypeAssertionError{"", "", t.string(), ""}) } if e._type != t { - panic(&TypeAssertionError{"", e._type._string, t._string, ""}) + panic(&TypeAssertionError{"", e._type.string(), t.string(), ""}) } if r != nil { if isDirectIface(t) { @@ -285,7 +285,7 @@ func assertI2E(inter *interfacetype, i iface, r *eface) { tab := i.tab if tab == nil { // explicit conversions require non-nil interface value. - panic(&TypeAssertionError{"", "", inter.typ._string, ""}) + panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) } r._type = tab._type r.data = i.data @@ -322,7 +322,7 @@ func assertI2I(inter *interfacetype, i iface, r *iface) { tab := i.tab if tab == nil { // explicit conversions require non-nil interface value. - panic(&TypeAssertionError{"", "", inter.typ._string, ""}) + panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) } if tab.inter == inter { r.tab = tab @@ -361,7 +361,7 @@ func assertE2I(inter *interfacetype, e eface, r *iface) { t := e._type if t == nil { // explicit conversions require non-nil interface value. - panic(&TypeAssertionError{"", "", inter.typ._string, ""}) + panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) } r.tab = getitab(inter, t, false) r.data = e.data @@ -402,7 +402,7 @@ func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) { func assertE2E(inter *interfacetype, e eface, r *eface) { if e._type == nil { // explicit conversions require non-nil interface value. - panic(&TypeAssertionError{"", "", inter.typ._string, ""}) + panic(&TypeAssertionError{"", "", inter.typ.string(), ""}) } *r = e } diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go index 685c29066b..f025ce1c68 100644 --- a/src/runtime/mbitmap.go +++ b/src/runtime/mbitmap.go @@ -461,11 +461,11 @@ func typeBitsBulkBarrier(typ *_type, p, size uintptr) { throw("runtime: typeBitsBulkBarrier without type") } if typ.size != size { - println("runtime: typeBitsBulkBarrier with type ", typ._string, " of size ", typ.size, " but memory size", size) + println("runtime: typeBitsBulkBarrier with type ", typ.string(), " of size ", typ.size, " but memory size", size) throw("runtime: invalid typeBitsBulkBarrier") } if typ.kind&kindGCProg != 0 { - println("runtime: typeBitsBulkBarrier with type ", typ._string, " with GC prog") + println("runtime: typeBitsBulkBarrier with type ", typ.string(), " with GC prog") throw("runtime: invalid typeBitsBulkBarrier") } if !writeBarrier.needed { @@ -916,7 +916,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) { } if nw == 0 { // No pointers! Caller was supposed to check. - println("runtime: invalid type ", typ._string) + println("runtime: invalid type ", typ.string()) throw("heapBitsSetType: called with non-pointer type") return } @@ -1100,7 +1100,7 @@ Phase4: if doubleCheck { end := heapBitsForAddr(x + size) if typ.kind&kindGCProg == 0 && (hbitp != end.bitp || (w == nw+2) != (end.shift == 2)) { - println("ended at wrong bitmap byte for", typ._string, "x", dataSize/typ.size) + println("ended at wrong bitmap byte for", typ.string(), "x", dataSize/typ.size) print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\n") print("w=", w, " nw=", nw, " b=", hex(b), " nb=", nb, " hb=", hex(hb), "\n") h0 := heapBitsForAddr(x) @@ -1136,7 +1136,7 @@ Phase4: } } if have != want { - println("mismatch writing bits for", typ._string, "x", dataSize/typ.size) + println("mismatch writing bits for", typ.string(), "x", dataSize/typ.size) print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\n") print("kindGCProg=", typ.kind&kindGCProg != 0, "\n") print("w=", w, " nw=", nw, " b=", hex(b), " nb=", nb, " hb=", hex(hb), "\n") diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go index f698e72709..e81650d842 100644 --- a/src/runtime/mfinal.go +++ b/src/runtime/mfinal.go @@ -274,7 +274,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) { throw("runtime.SetFinalizer: first argument is nil") } if etyp.kind&kindMask != kindPtr { - throw("runtime.SetFinalizer: first argument is " + etyp._string + ", not pointer") + throw("runtime.SetFinalizer: first argument is " + etyp.string() + ", not pointer") } ot := (*ptrtype)(unsafe.Pointer(etyp)) if ot.elem == nil { @@ -328,14 +328,14 @@ func SetFinalizer(obj interface{}, finalizer interface{}) { } if ftyp.kind&kindMask != kindFunc { - throw("runtime.SetFinalizer: second argument is " + ftyp._string + ", not a function") + throw("runtime.SetFinalizer: second argument is " + ftyp.string() + ", not a function") } ft := (*functype)(unsafe.Pointer(ftyp)) if ft.dotdotdot() { - throw("runtime.SetFinalizer: cannot pass " + etyp._string + " to finalizer " + ftyp._string + " because dotdotdot") + throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string() + " because dotdotdot") } if ft.dotdotdot() || ft.inCount != 1 { - throw("runtime.SetFinalizer: cannot pass " + etyp._string + " to finalizer " + ftyp._string) + throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string()) } fint := ft.in()[0] switch { @@ -358,7 +358,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) { goto okarg } } - throw("runtime.SetFinalizer: cannot pass " + etyp._string + " to finalizer " + ftyp._string) + throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string()) okarg: // compute size needed for return parameters nret := uintptr(0) diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go index f3b9b4bc78..c3e4e2cb87 100644 --- a/src/runtime/mprof.go +++ b/src/runtime/mprof.go @@ -624,7 +624,7 @@ func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) { if typ == nil { print("tracealloc(", p, ", ", hex(size), ")\n") } else { - print("tracealloc(", p, ", ", hex(size), ", ", typ._string, ")\n") + print("tracealloc(", p, ", ", hex(size), ", ", typ.string(), ")\n") } if gp.m.curg == nil || gp == gp.m.curg { goroutineheader(gp) diff --git a/src/runtime/type.go b/src/runtime/type.go index 31f7ff81b8..0b28fa6d43 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -8,10 +8,18 @@ package runtime import "unsafe" -// tflag is documented in ../reflect/type.go. +// 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 type tflag uint8 -const tflagUncommon tflag = 1 +const ( + tflagUncommon tflag = 1 << 0 + tflagExtraStar tflag = 1 << 1 +) // Needs to be in sync with ../cmd/compile/internal/ld/decodesym.go:/^func.commonsize, // ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and @@ -28,8 +36,17 @@ type _type struct { // gcdata stores the GC type data for the garbage collector. // If the KindGCProg bit is set in kind, gcdata is a GC program. // Otherwise it is a ptrmask bitmap. See mbitmap.go for details. - gcdata *byte - _string string + gcdata *byte + str nameOff + _ int32 +} + +func (t *_type) string() string { + s := t.nameOff(t.str).name() + if t.tflag&tflagExtraStar != 0 { + return s[1:] + } + return s } func (t *_type) uncommon() *uncommontype { @@ -99,33 +116,34 @@ func hasPrefix(s, prefix string) bool { } func (t *_type) name() string { - if hasPrefix(t._string, "map[") { + s := t.string() + if hasPrefix(s, "map[") { return "" } - if hasPrefix(t._string, "struct {") { + if hasPrefix(s, "struct {") { return "" } - if hasPrefix(t._string, "chan ") { + if hasPrefix(s, "chan ") { return "" } - if hasPrefix(t._string, "chan<-") { + if hasPrefix(s, "chan<-") { return "" } - if hasPrefix(t._string, "func(") { + if hasPrefix(s, "func(") { return "" } - switch t._string[0] { + switch s[0] { case '[', '*', '<': return "" } - i := len(t._string) - 1 + i := len(s) - 1 for i >= 0 { - if t._string[i] == '.' { + if s[i] == '.' { break } i-- } - return t._string[i+1:] + return s[i+1:] } // reflectOffs holds type offsets defined at run time by the reflect package. @@ -497,7 +515,7 @@ func typesEqual(t, v *_type) bool { if kind != v.kind&kindMask { return false } - if t._string != v._string { + if t.string() != v.string() { return false } ut := t.uncommon() -- cgit v1.3-5-g9baa From c165988360457553ccbfa4a09919de3262a4438a Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Thu, 7 Apr 2016 21:37:45 -0400 Subject: cmd/compile, etc: use nameOff in uncommonType linux/amd64 PIE: cmd/go: -62KB (0.5%) jujud: -550KB (0.7%) For #6853. Change-Id: Ieb67982abce5832e24b997506f0ae7108f747108 Reviewed-on: https://go-review.googlesource.com/22371 Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/cmd/compile/internal/gc/reflect.go | 15 ++++++--------- src/cmd/link/internal/ld/decodesym.go | 6 +++--- src/cmd/link/internal/ld/symtab.go | 5 +++++ src/reflect/type.go | 21 +++++++++------------ src/runtime/heapdump.go | 4 ++-- src/runtime/iface.go | 2 +- src/runtime/type.go | 6 ++++-- 7 files changed, 30 insertions(+), 29 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index 1643c2ce4b..3cd769fd2d 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -75,7 +75,7 @@ func uncommonSize(t *Type) int { // Sizeof(runtime.uncommontype{}) if t.Sym == nil && len(methods(t)) == 0 { return 0 } - return 2 * Widthptr + return 4 + 2 + 2 } func makefield(name string, t *Type) *Field { @@ -463,6 +463,9 @@ func dgopkgpathLSym(s *obj.LSym, ot int, pkg *Pkg) int { // dgopkgpathOffLSym writes an offset relocation in s at offset ot to the pkg path symbol. func dgopkgpathOffLSym(s *obj.LSym, ot int, pkg *Pkg) int { + if pkg == nil { + return duintxxLSym(s, ot, 0, 4) + } if pkg == localpkg && myimportpath == "" { // If we don't know the full import path of the package being compiled // (i.e. -p was not passed on the compiler command line), emit a reference to @@ -597,12 +600,9 @@ func dextratype(s *Sym, ot int, t *Type, dataAdd int) int { dtypesym(a.type_) } - ot = dgopkgpath(s, ot, typePkg(t)) + ot = dgopkgpathOffLSym(Linksym(s), ot, typePkg(t)) - dataAdd += Widthptr + 2 + 2 - if Widthptr == 8 { - dataAdd += 4 - } + dataAdd += 4 + 2 + 2 mcount := len(m) if mcount != int(uint16(mcount)) { Fatalf("too many methods on %s: %d", t, mcount) @@ -613,9 +613,6 @@ func dextratype(s *Sym, ot int, t *Type, dataAdd int) int { ot = duint16(s, ot, uint16(mcount)) ot = duint16(s, ot, uint16(dataAdd)) - if Widthptr == 8 { - ot = duint32(s, ot, 0) // align for following pointers - } return ot } diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index 330aa6dc13..3ec488bbe8 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -61,7 +61,7 @@ func decode_inuxi(p []byte, sz int) uint64 { func commonsize() int { return 4*SysArch.PtrSize + 8 + 8 } // runtime._type func structfieldSize() int { return 3 * SysArch.PtrSize } // runtime.structfield -func uncommonSize() int { return 2 * SysArch.PtrSize } // runtime.uncommontype +func uncommonSize() int { return 4 + 2 + 2 } // runtime.uncommontype // Type.commonType.kind func decodetype_kind(s *LSym) uint8 { @@ -361,8 +361,8 @@ func decodetype_methods(s *LSym) []methodsig { // just Sizeof(rtype) } - mcount := int(decode_inuxi(s.P[off+SysArch.PtrSize:], 2)) - moff := int(decode_inuxi(s.P[off+SysArch.PtrSize+2:], 2)) + 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/symtab.go b/src/cmd/link/internal/ld/symtab.go index acc238f698..94a6d0ab29 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -435,6 +435,11 @@ func symtab() { s.Outer = symtype } + 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 diff --git a/src/reflect/type.go b/src/reflect/type.go index b1758e6913..ff6ff14c83 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -311,9 +311,9 @@ type method struct { // Using a pointer to this struct reduces the overall size required // to describe an unnamed type with no methods. type uncommonType struct { - pkgPath name // import path; empty for built-in types like int, string - mcount uint16 // number of methods - moff uint16 // offset from this uncommontype to [mcount]method + pkgPath nameOff // import path; empty for built-in types like int, string + mcount uint16 // number of methods + moff uint16 // offset from this uncommontype to [mcount]method } // ChanDir represents a channel type's direction. @@ -613,13 +613,6 @@ func (t *uncommonType) methods() []method { return (*[1 << 16]method)(add(unsafe.Pointer(t), uintptr(t.moff)))[:t.mcount:t.mcount] } -func (t *uncommonType) PkgPath() string { - if t == nil { - return "" - } - return t.pkgPath.name() -} - // resolveNameOff resolves a name offset from a base pointer. // The (*rtype).nameOff method is a convenience wrapper for this function. // Implemented in the runtime package. @@ -799,7 +792,7 @@ func (t *rtype) Method(i int) (m Method) { if !pname.isExported() { m.PkgPath = pname.pkgPath() if m.PkgPath == "" { - m.PkgPath = ut.pkgPath.name() + m.PkgPath = t.nameOff(ut.pkgPath).name() } fl |= flagStickyRO } @@ -846,7 +839,11 @@ func (t *rtype) MethodByName(name string) (m Method, ok bool) { } func (t *rtype) PkgPath() string { - return t.uncommon().PkgPath() + ut := t.uncommon() + if ut == nil { + return "" + } + return t.nameOff(ut.pkgPath).name() } func hasPrefix(s, prefix string) bool { diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go index 1db29d7cb4..0afab09095 100644 --- a/src/runtime/heapdump.go +++ b/src/runtime/heapdump.go @@ -183,10 +183,10 @@ func dumptype(t *_type) { dumpint(tagType) dumpint(uint64(uintptr(unsafe.Pointer(t)))) dumpint(uint64(t.size)) - if x := t.uncommon(); x == nil || x.pkgpath.name() == "" { + if x := t.uncommon(); x == nil || t.nameOff(x.pkgpath).name() == "" { dumpstr(t.string()) } else { - pkgpathstr := x.pkgpath.name() + pkgpathstr := t.nameOff(x.pkgpath).name() pkgpath := stringStructOf(&pkgpathstr) namestr := t.name() name := stringStructOf(&namestr) diff --git a/src/runtime/iface.go b/src/runtime/iface.go index 007c1ed174..b57d1cc63c 100644 --- a/src/runtime/iface.go +++ b/src/runtime/iface.go @@ -112,7 +112,7 @@ func additab(m *itab, locked, canfail bool) { if typ.typeOff(t.mtyp) == itype && tname.name() == iname { pkgPath := tname.pkgPath() if pkgPath == "" { - pkgPath = x.pkgpath.name() + pkgPath = typ.nameOff(x.pkgpath).name() } if tname.isExported() || pkgPath == ipkg { if m != nil { diff --git a/src/runtime/type.go b/src/runtime/type.go index 0b28fa6d43..9e4c40553a 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -304,7 +304,7 @@ type method struct { } type uncommontype struct { - pkgpath name + pkgpath nameOff mcount uint16 // number of methods moff uint16 // offset from this uncommontype to [mcount]method } @@ -524,7 +524,9 @@ func typesEqual(t, v *_type) bool { if ut == nil || uv == nil { return false } - if ut.pkgpath.name() != uv.pkgpath.name() { + pkgpatht := t.nameOff(ut.pkgpath).name() + pkgpathv := v.nameOff(uv.pkgpath).name() + if pkgpatht != pkgpathv { return false } } -- cgit v1.3-5-g9baa From d224e98d9ac969e733f5578dce3e1831c5c84f45 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 22 Apr 2016 18:49:59 -0700 Subject: cmd/link: add -dumpdep flag to dump linker dependency graph This is what led to https://golang.org/cl/20763 and https://golang.org/cl/20765 to shrink binary sizes. Change-Id: Id360d474e6153cfe32a525b0a720810fd113195b Reviewed-on: https://go-review.googlesource.com/22392 Reviewed-by: David Crawshaw --- src/cmd/link/internal/ld/deadcode.go | 7 +++++++ src/cmd/link/internal/ld/lib.go | 1 + src/cmd/link/internal/ld/pobj.go | 1 + 3 files changed, 9 insertions(+) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index 6a70ff581f..aaed6cde21 100644 --- a/src/cmd/link/internal/ld/deadcode.go +++ b/src/cmd/link/internal/ld/deadcode.go @@ -196,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) diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 77db672bfd..f7b9b79c2f 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -196,6 +196,7 @@ var ( Funcalign int iscgo bool elfglobalsymndx int + flag_dumpdep bool flag_installsuffix string flag_race int flag_msan int diff --git a/src/cmd/link/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go index f4fb4d4845..b64bb5deaf 100644 --- a/src/cmd/link/internal/ld/pobj.go +++ b/src/cmd/link/internal/ld/pobj.go @@ -90,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) -- cgit v1.3-5-g9baa From 96b8f70e22e103c11fbb89ba6df9d229d24cdbc2 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Tue, 26 Apr 2016 10:53:25 -0400 Subject: cmd/link: correctly decode name length The linker was incorrectly decoding type name lengths, causing typelinks to be sorted out of order and in cases where the name was the exact right length, linker panics. Added a test to the reflect package that causes TestTypelinksSorted to fail before this CL. It's not the exact failure seen in #15448 but it has the same cause: decodetype_name calculating the wrong length. The equivalent decoders in reflect/type.go and runtime/type.go have the parenthesis in the right place. Fixes #15448 Change-Id: I33257633d812b7d2091393cb9d6cc8a73e0138c8 Reviewed-on: https://go-review.googlesource.com/22403 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick Reviewed-by: Russ Cox TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/decodesym.go | 2 +- src/reflect/all_test.go | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go index 3ec488bbe8..551ff802d7 100644 --- a/src/cmd/link/internal/ld/decodesym.go +++ b/src/cmd/link/internal/ld/decodesym.go @@ -239,7 +239,7 @@ 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]) } diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index e88bc880e2..aff8ea253b 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -5651,6 +5651,8 @@ func TestChanAlloc(t *testing.T) { // allocs < 0.5 condition will trigger and this test should be fixed. } +type TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678 int + type nameTest struct { v interface{} want string @@ -5664,6 +5666,7 @@ var nameTests = []nameTest{ {(func() D1)(nil), ""}, {(<-chan D1)(nil), ""}, {(chan<- D1)(nil), ""}, + {TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678(0), "TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678"}, } func TestNames(t *testing.T) { -- cgit v1.3-5-g9baa From 55154cf0b27e3c48e7cf7654c890868a95e7eed6 Mon Sep 17 00:00:00 2001 From: Michael Munday Date: Wed, 13 Apr 2016 13:34:41 -0400 Subject: cmd/link: fix gdb backtrace on architectures using a link register Also adds TestGdbBacktrace to the runtime package. Dwarf modifications written by Bryan Chan (@bryanpkc) who is also at IBM and covered by the same CLA. Fixes #14628 Change-Id: I106a1f704c3745a31f29cdadb0032e3905829850 Reviewed-on: https://go-review.googlesource.com/20193 Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot --- src/cmd/link/internal/ld/dwarf.go | 58 ++++++++++++------ src/runtime/runtime-gdb_test.go | 122 +++++++++++++++++++++++++++++++++----- 2 files changed, 145 insertions(+), 35 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 0202df664a..bf1a7e74c1 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -1619,14 +1619,13 @@ func writelines(prev *LSym) *LSym { * 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: @@ -1654,36 +1653,42 @@ func writeframes(prev *LSym) *LSym { prev.Next = fs // Emit the CIE, Section 6.4.1 - Adduint32(Ctxt, fs, CIERESERVE) // initial length, must be multiple of thearch.ptrsize + cieReserve := uint32(16) + if haslinkregister() { + 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) // guess + sleb128put(fs, dataAlignmentFactor) // all CFI offset calculations include multiplication with this factor uleb128put(fs, int64(Thearch.Dwarfreglr)) // return_address_register - Adduint8(Ctxt, fs, DW_CFA_def_cfa) - - uleb128put(fs, int64(Thearch.Dwarfregsp)) // register SP (**ABI-dependent, defined in l.h) + 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(fs, int64(0)) // offset - } else { - uleb128put(fs, int64(SysArch.PtrSize)) // offset - } + uleb128put(fs, int64(0)) // ...plus a 0 offset. - Adduint8(Ctxt, fs, DW_CFA_offset_extended) - uleb128put(fs, int64(Thearch.Dwarfreglr)) // return address - if haslinkregister() { - uleb128put(fs, int64(0)/DATAALIGNMENTFACTOR) // at cfa - 0 + 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(fs, int64(-SysArch.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 + 4 - fs.Size + 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) } Addbytes(Ctxt, fs, zeros[:pad]) @@ -1712,6 +1717,21 @@ func writeframes(prev *LSym) *LSym { } 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(SysArch.PtrSize)+int64(pcsp.value)) diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index 7cfcefc2c2..4f82646dbb 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -3,6 +3,7 @@ package runtime_test import ( "bytes" "fmt" + "internal/testenv" "io/ioutil" "os" "os/exec" @@ -13,19 +14,22 @@ import ( "testing" ) -func checkGdbPython(t *testing.T) { - cmd := exec.Command("gdb", "-nx", "-q", "--batch", "-iex", "python import sys; print('go gdb python support')") - out, err := cmd.CombinedOutput() - - if err != nil { - t.Skipf("skipping due to issue running gdb: %v", err) +func checkGdbEnvironment(t *testing.T) { + testenv.MustHaveGoBuild(t) + if runtime.GOOS == "darwin" { + t.Skip("gdb does not work on darwin") } - if string(out) != "go gdb python support\n" { - t.Skipf("skipping due to lack of python gdb support: %s", out) + if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final { + t.Skip("gdb test can fail with GOROOT_FINAL pending") } +} +func checkGdbVersion(t *testing.T) { // Issue 11214 reports various failures with older versions of gdb. - out, err = exec.Command("gdb", "--version").CombinedOutput() + out, err := exec.Command("gdb", "--version").CombinedOutput() + if err != nil { + t.Skipf("skipping: error executing gdb: %v", err) + } re := regexp.MustCompile(`([0-9]+)\.([0-9]+)`) matches := re.FindSubmatch(out) if len(matches) < 3 { @@ -42,6 +46,18 @@ func checkGdbPython(t *testing.T) { t.Logf("gdb version %d.%d", major, minor) } +func checkGdbPython(t *testing.T) { + cmd := exec.Command("gdb", "-nx", "-q", "--batch", "-iex", "python import sys; print('go gdb python support')") + out, err := cmd.CombinedOutput() + + if err != nil { + t.Skipf("skipping due to issue running gdb: %v", err) + } + if string(out) != "go gdb python support\n" { + t.Skipf("skipping due to lack of python gdb support: %s", out) + } +} + const helloSource = ` package main import "fmt" @@ -57,13 +73,8 @@ func main() { ` func TestGdbPython(t *testing.T) { - if runtime.GOOS == "darwin" { - t.Skip("gdb does not work on darwin") - } - if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final { - t.Skip("gdb test can fail with GOROOT_FINAL pending") - } - + checkGdbEnvironment(t) + checkGdbVersion(t) checkGdbPython(t) dir, err := ioutil.TempDir("", "go-build") @@ -162,3 +173,82 @@ func TestGdbPython(t *testing.T) { t.Logf("gdb cannot backtrace for GOARCH=%s, skipped goroutine backtrace test", runtime.GOARCH) } } + +const backtraceSource = ` +package main + +//go:noinline +func aaa() bool { return bbb() } + +//go:noinline +func bbb() bool { return ccc() } + +//go:noinline +func ccc() bool { return ddd() } + +//go:noinline +func ddd() bool { return f() } + +//go:noinline +func eee() bool { return true } + +var f = eee + +func main() { + _ = aaa() +} +` + +// TestGdbBacktrace tests that gdb can unwind the stack correctly +// using only the DWARF debug info. +func TestGdbBacktrace(t *testing.T) { + checkGdbEnvironment(t) + checkGdbVersion(t) + + dir, err := ioutil.TempDir("", "go-build") + if err != nil { + t.Fatalf("failed to create temp directory: %v", err) + } + defer os.RemoveAll(dir) + + // Build the source code. + src := filepath.Join(dir, "main.go") + err = ioutil.WriteFile(src, []byte(backtraceSource), 0644) + if err != nil { + t.Fatalf("failed to create file: %v", err) + } + cmd := exec.Command("go", "build", "-o", "a.exe") + cmd.Dir = dir + out, err := testEnv(cmd).CombinedOutput() + if err != nil { + t.Fatalf("building source %v\n%s", err, out) + } + + // Execute gdb commands. + args := []string{"-nx", "-batch", + "-ex", "break main.eee", + "-ex", "run", + "-ex", "backtrace", + "-ex", "continue", + filepath.Join(dir, "a.exe"), + } + got, _ := exec.Command("gdb", args...).CombinedOutput() + + // Check that the backtrace matches the source code. + bt := []string{ + "eee", + "ddd", + "ccc", + "bbb", + "aaa", + "main", + } + for i, name := range bt { + s := fmt.Sprintf("#%v.*main\\.%v", i, name) + re := regexp.MustCompile(s) + if found := re.Find(got) != nil; !found { + t.Errorf("could not find '%v' in backtrace", s) + t.Fatalf("gdb output:\n%v", string(got)) + } + } +} -- cgit v1.3-5-g9baa From 3a72d626a8bae104c658f361d97f992f609d91e7 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Tue, 26 Apr 2016 21:37:49 +1200 Subject: cmd/link: pass -no-pie (if supported) when creating a race-enabled executable. Fixes #15443 Change-Id: Ia3593104fc1a4255926ae5675c25390604b44b7b Reviewed-on: https://go-review.googlesource.com/22453 Run-TryBot: Michael Hudson-Doyle TryBot-Result: Gobot Gobot Reviewed-by: Dmitry Vyukov Reviewed-by: Ian Lance Taylor --- src/cmd/link/internal/ld/lib.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/cmd/link') diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index f7b9b79c2f..53428bb1c6 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1204,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) -- cgit v1.3-5-g9baa From 9629f55fbbfb4052ea24c247cbd5db49ba2f389e Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Tue, 26 Apr 2016 15:17:56 -0400 Subject: cmd/link: remove absolute address for c-archive on darwin/arm Now it is possible to build a c-archive as PIC on darwin/arm (this is now the default). Then the system linker can link the binary using the archive as PIE. Fixes #12896. Change-Id: Iad84131572422190f5fa036e7d71910dc155f155 Reviewed-on: https://go-review.googlesource.com/22461 Reviewed-by: David Crawshaw --- src/cmd/go/build.go | 5 +++++ src/cmd/link/internal/arm/asm.go | 30 ++++++++++++++++++++++++++++++ src/cmd/link/internal/ld/data.go | 3 +++ src/cmd/link/internal/ld/macho.go | 7 +++++-- src/runtime/cgo/signal_darwin_armx.go | 6 +++++- 5 files changed, 48 insertions(+), 3 deletions(-) (limited to 'src/cmd/link') diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go index 4aaad04b3a..b8c12db196 100644 --- a/src/cmd/go/build.go +++ b/src/cmd/go/build.go @@ -334,6 +334,11 @@ func buildModeInit() { } return p } + switch platform { + case "darwin/arm": + codegenArg = "-shared" + default: + } exeSuffix = ".a" ldBuildmode = "c-archive" case "c-shared": diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go index 069812fcef..aafdd9bc3d 100644 --- a/src/cmd/link/internal/arm/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -330,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) diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index dbd5ad0b75..8964757846 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -560,6 +560,9 @@ 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) } diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index 310435e49e..53cc96275d 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -79,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 @@ -350,8 +352,9 @@ func machoshbits(mseg *MachoSeg, sect *Section, segname string) { var msect *MachoSect if sect.Rwx&1 == 0 && segname != "__DWARF" && (SysArch.Family == sys.ARM64 || - (SysArch.Family == sys.AMD64 && (Buildmode == BuildmodeCShared || Buildmode == BuildmodeCArchive))) { - // Darwin external linker on arm64 and on amd64 in c-shared/c-archive buildmode + (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") diff --git a/src/runtime/cgo/signal_darwin_armx.go b/src/runtime/cgo/signal_darwin_armx.go index 9c1ba5dee1..9f6741eb08 100644 --- a/src/runtime/cgo/signal_darwin_armx.go +++ b/src/runtime/cgo/signal_darwin_armx.go @@ -13,10 +13,14 @@ import "unsafe" //go:linkname x_cgo_panicmem x_cgo_panicmem var x_cgo_panicmem uintptr +// use a pointer to avoid relocation of external symbol in __TEXT +// make linker happy +var _cgo_panicmem = &x_cgo_panicmem + // TODO(crawshaw): move this into x_cgo_init, it will not run until // runtime has finished loading, which may be after its use. func init() { - x_cgo_panicmem = funcPC(panicmem) + *_cgo_panicmem = funcPC(panicmem) } func funcPC(f interface{}) uintptr { -- cgit v1.3-5-g9baa