[dev.debug] cmd/link: let the linker combine .debug_ranges, remove globals

The linker is pretty good at combining a bunch of symbols into a
section, so let it do .debug_ranges the normal way. Along the way,
remove a bunch of globals that were only used by one function that would
only be called once per invocation.

Change-Id: I1a528a438b193c41e7c444e8830516b07f11affc
Reviewed-on: https://go-review.googlesource.com/43890
Reviewed-by: Alessandro Arzilli <alessandro.arzilli@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index 4523323..bf219f7 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -592,15 +592,7 @@
 			}
 
 		case objabi.R_DWARFREF:
-			var sectName string
-			var vaddr int64
-			switch {
-			case r.Sym.Sect != nil:
-				sectName = r.Sym.Sect.Name
-				vaddr = int64(r.Sym.Sect.Vaddr)
-			case r.Sym.Type == SDWARFRANGE:
-				sectName = ".debug_ranges"
-			default:
+			if r.Sym.Sect == nil {
 				Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name)
 			}
 
@@ -615,8 +607,8 @@
 					r.Type = objabi.R_ADDR
 				}
 
-				r.Xsym = ctxt.Syms.ROLookup(sectName, 0)
-				r.Xadd = r.Add + Symaddr(r.Sym) - vaddr
+				r.Xsym = ctxt.Syms.ROLookup(r.Sym.Sect.Name, 0)
+				r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr)
 
 				o = r.Xadd
 				rs = r.Xsym
@@ -625,7 +617,7 @@
 				}
 				break
 			}
-			o = Symaddr(r.Sym) + r.Add - vaddr
+			o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr)
 
 		case objabi.R_WEAKADDROFF:
 			if !r.Sym.Attr.Reachable() {
@@ -1843,9 +1835,9 @@
 
 	dwarfgeneratedebugsyms(ctxt)
 
-	var s *Symbol
 	var i int
-	for i, s = range dwarfp {
+	for ; i < len(dwarfp); i++ {
+		s := dwarfp[i]
 		if s.Type != SDWARFSECT {
 			break
 		}
@@ -1862,13 +1854,24 @@
 	}
 	checkdatsize(ctxt, datsize, SDWARFSECT)
 
-	if i < len(dwarfp) {
-		sect = addsection(&Segdwarf, ".debug_info", 04)
+	for i < len(dwarfp) {
+		curType := dwarfp[i].Type
+		var sect *Section
+		switch curType {
+		case SDWARFINFO:
+			sect = addsection(&Segdwarf, ".debug_info", 04)
+		case SDWARFRANGE:
+			sect = addsection(&Segdwarf, ".debug_ranges", 04)
+		default:
+			Errorf(dwarfp[i], "unknown DWARF section %v", curType)
+		}
+
 		sect.Align = 1
 		datsize = Rnd(datsize, int64(sect.Align))
 		sect.Vaddr = uint64(datsize)
-		for _, s := range dwarfp[i:] {
-			if s.Type != SDWARFINFO {
+		for ; i < len(dwarfp); i++ {
+			s := dwarfp[i]
+			if s.Type != curType {
 				break
 			}
 			s.Sect = sect
@@ -1878,7 +1881,7 @@
 			datsize += s.Size
 		}
 		sect.Length = uint64(datsize) - sect.Vaddr
-		checkdatsize(ctxt, datsize, SDWARFINFO)
+		checkdatsize(ctxt, datsize, curType)
 	}
 
 	/* number the sections */
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index ba8ace5..9b11fdc 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -67,26 +67,15 @@
 	r.Add = ofs
 }
 
-/*
- * Offsets and sizes of the debug_* sections in the cout file.
- */
-var abbrevsym *Symbol
-var arangessec *Symbol
-var framesec *Symbol
-var infosec *Symbol
-var linesec *Symbol
-var rangesec *Symbol
-
 var gdbscript string
 
 var dwarfp []*Symbol
 
-func writeabbrev(ctxt *Link, syms []*Symbol) []*Symbol {
+func writeabbrev(ctxt *Link) *Symbol {
 	s := ctxt.Syms.Lookup(".debug_abbrev", 0)
 	s.Type = SDWARFSECT
-	abbrevsym = s
 	Addbytes(s, dwarf.GetAbbrev())
-	return append(syms, s)
+	return s
 }
 
 /*
@@ -993,13 +982,10 @@
 
 func writelines(ctxt *Link, syms []*Symbol) ([]*Symbol, []*Symbol) {
 	var dwarfctxt dwarf.Context = dwctxt{ctxt}
-	if linesec == nil {
-		linesec = ctxt.Syms.Lookup(".debug_line", 0)
-	}
-	linesec.Type = SDWARFSECT
-	linesec.R = linesec.R[:0]
+	ls := ctxt.Syms.Lookup(".debug_line", 0)
+	ls.Type = SDWARFSECT
+	ls.R = ls.R[:0]
 
-	ls := linesec
 	syms = append(syms, ls)
 	var funcs []*Symbol
 
@@ -1019,7 +1005,7 @@
 
 	dwinfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, "go", 0)
 	newattr(dwinfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(lang), 0)
-	newattr(dwinfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, 0, linesec)
+	newattr(dwinfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, 0, ls)
 	newattr(dwinfo, dwarf.DW_AT_low_pc, dwarf.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()
@@ -1178,12 +1164,9 @@
 
 func writeframes(ctxt *Link, syms []*Symbol) []*Symbol {
 	var dwarfctxt dwarf.Context = dwctxt{ctxt}
-	if framesec == nil {
-		framesec = ctxt.Syms.Lookup(".debug_frame", 0)
-	}
-	framesec.Type = SDWARFSECT
-	framesec.R = framesec.R[:0]
-	fs := framesec
+	fs := ctxt.Syms.Lookup(".debug_frame", 0)
+	fs.Type = SDWARFSECT
+	fs.R = fs.R[:0]
 	syms = append(syms, fs)
 
 	// Emit the CIE, Section 6.4.1
@@ -1280,7 +1263,7 @@
 		//	ptrsize: address range
 		Adduint32(ctxt, fs, uint32(4+2*SysArch.PtrSize+len(deltaBuf))) // length (excludes itself)
 		if Linkmode == LinkExternal {
-			adddwarfref(ctxt, fs, framesec, 4)
+			adddwarfref(ctxt, fs, fs, 4)
 		} else {
 			Adduint32(ctxt, fs, 0) // CIE offset
 		}
@@ -1292,27 +1275,24 @@
 }
 
 func writeranges(ctxt *Link, syms []*Symbol) []*Symbol {
-	if rangesec == nil {
-		rangesec = ctxt.Syms.Lookup(".debug_ranges", 0)
-	}
-	rangesec.Type = SDWARFSECT
-	rangesec.Attr |= AttrReachable
-	rangesec.R = rangesec.R[:0]
-
+	empty := true
 	for _, s := range ctxt.Textp {
 		rangeSym := ctxt.Syms.Lookup(dwarf.RangePrefix+s.Name, int(s.Version))
-		rangeSym.Attr |= AttrReachable
-		rangeSym.Type = SDWARFRANGE
-		rangeSym.Value = rangesec.Size
-		rangesec.P = append(rangesec.P, rangeSym.P...)
-		for _, r := range rangeSym.R {
-			r.Off += int32(rangesec.Size)
-			rangesec.R = append(rangesec.R, r)
+		if rangeSym.Size == 0 {
+			continue
 		}
-		rangesec.Size += rangeSym.Size
+		rangeSym.Attr |= AttrReachable | AttrNotInSymbolTable
+		rangeSym.Type = SDWARFRANGE
+		syms = append(syms, rangeSym)
+		empty = false
 	}
-	if rangesec.Size > 0 {
+	if !empty {
 		// PE does not like empty sections
+		rangesec := ctxt.Syms.Lookup(".debug_ranges", 0)
+		rangesec.Type = SDWARFRANGE
+		rangesec.Attr |= AttrReachable
+		rangesec.R = rangesec.R[:0]
+
 		syms = append(syms, rangesec)
 	}
 	return syms
@@ -1325,18 +1305,14 @@
 	COMPUNITHEADERSIZE = 4 + 2 + 4 + 1
 )
 
-func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol) []*Symbol {
-	if infosec == nil {
-		infosec = ctxt.Syms.Lookup(".debug_info", 0)
-	}
+func writeinfo(ctxt *Link, syms []*Symbol, funcs []*Symbol, abbrevsym *Symbol) []*Symbol {
+	infosec := ctxt.Syms.Lookup(".debug_info", 0)
 	infosec.R = infosec.R[:0]
 	infosec.Type = SDWARFINFO
 	infosec.Attr |= AttrReachable
 	syms = append(syms, infosec)
 
-	if arangessec == nil {
-		arangessec = ctxt.Syms.Lookup(".dwarfaranges", 0)
-	}
+	arangessec := ctxt.Syms.Lookup(".dwarfaranges", 0)
 	arangessec.R = arangessec.R[:0]
 
 	var dwarfctxt dwarf.Context = dwctxt{ctxt}
@@ -1577,10 +1553,10 @@
 
 	genasmsym(ctxt, defdwsymb)
 
-	syms := writeabbrev(ctxt, nil)
+	abbrev := writeabbrev(ctxt)
+	syms := []*Symbol{abbrev}
 	syms, funcs := writelines(ctxt, syms)
 	syms = writeframes(ctxt, syms)
-	syms = writeranges(ctxt, syms)
 
 	synthesizestringtypes(ctxt, dwtypes.Child)
 	synthesizeslicetypes(ctxt, dwtypes.Child)
@@ -1596,13 +1572,14 @@
 
 	// Need to reorder symbols so SDWARFINFO is after all SDWARFSECT
 	// (but we need to generate dies before writepub)
-	infosyms := writeinfo(ctxt, nil, funcs)
+	infosyms := writeinfo(ctxt, nil, funcs, abbrev)
 
 	syms = writepub(ctxt, ".debug_pubnames", ispubname, syms)
 	syms = writepub(ctxt, ".debug_pubtypes", ispubtype, syms)
 	syms = writearanges(ctxt, syms)
 	syms = writegdbscript(ctxt, syms)
 	syms = append(syms, infosyms...)
+	syms = writeranges(ctxt, syms)
 	dwarfp = syms
 }