package ld
import (
+ "bytes"
"cmd/internal/gcprog"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/sym"
+ "compress/zlib"
+ "encoding/binary"
"fmt"
"log"
"os"
}
}
+ // This doesn't distinguish the memory size from the file
+ // size, and it lays out the file based on Symbol.Value, which
+ // is the virtual address. DWARF compression changes file sizes,
+ // so dwarfcompress will fix this up later if necessary.
eaddr := addr + size
for _, s := range syms {
if s.Attr.SubSymbol() {
ctxt.Logf("trampoline %s inserted\n", s)
}
}
+
+// compressSyms compresses syms and returns the contents of the
+// compressed section. If the section would get larger, it returns nil.
+func compressSyms(ctxt *Link, syms []*sym.Symbol) []byte {
+ var total int64
+ for _, sym := range syms {
+ total += sym.Size
+ }
+
+ var buf bytes.Buffer
+ buf.Write([]byte("ZLIB"))
+ var sizeBytes [8]byte
+ binary.BigEndian.PutUint64(sizeBytes[:], uint64(total))
+ buf.Write(sizeBytes[:])
+
+ z := zlib.NewWriter(&buf)
+ for _, sym := range syms {
+ if _, err := z.Write(sym.P); err != nil {
+ log.Fatalf("compression failed: %s", err)
+ }
+ for i := sym.Size - int64(len(sym.P)); i > 0; {
+ b := zeros[:]
+ if i < int64(len(b)) {
+ b = b[:i]
+ }
+ n, err := z.Write(b)
+ if err != nil {
+ log.Fatalf("compression failed: %s", err)
+ }
+ i -= int64(n)
+ }
+ }
+ if err := z.Close(); err != nil {
+ log.Fatalf("compression failed: %s", err)
+ }
+ if int64(buf.Len()) >= total {
+ // Compression didn't save any space.
+ return nil
+ }
+ return buf.Bytes()
+}
return
}
- Addstring(shstrtab, ".debug_abbrev")
- Addstring(shstrtab, ".debug_frame")
- Addstring(shstrtab, ".debug_info")
- Addstring(shstrtab, ".debug_loc")
- Addstring(shstrtab, ".debug_line")
- Addstring(shstrtab, ".debug_pubnames")
- Addstring(shstrtab, ".debug_pubtypes")
- Addstring(shstrtab, ".debug_gdb_scripts")
- Addstring(shstrtab, ".debug_ranges")
- if ctxt.LinkMode == LinkExternal {
- Addstring(shstrtab, elfRelType+".debug_info")
- Addstring(shstrtab, elfRelType+".debug_loc")
- Addstring(shstrtab, elfRelType+".debug_line")
- Addstring(shstrtab, elfRelType+".debug_frame")
- Addstring(shstrtab, elfRelType+".debug_pubnames")
- Addstring(shstrtab, elfRelType+".debug_pubtypes")
- Addstring(shstrtab, elfRelType+".debug_ranges")
+ secs := []string{"abbrev", "frame", "info", "loc", "line", "pubnames", "pubtypes", "gdb_scripts", "ranges"}
+ for _, sec := range secs {
+ Addstring(shstrtab, ".debug_"+sec)
+ if ctxt.LinkMode == LinkExternal {
+ Addstring(shstrtab, elfRelType+".debug_"+sec)
+ } else {
+ Addstring(shstrtab, ".zdebug_"+sec)
+ }
}
}
if ctxt.LinkMode != LinkExternal {
return
}
+
s := ctxt.Syms.Lookup(".debug_info", 0)
putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
s = ctxt.Syms.Lookup(".debug_abbrev", 0)
putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
}
}
+
+// dwarfcompress compresses the DWARF sections. This must happen after
+// relocations are applied. After this, dwarfp will contain a
+// different (new) set of symbols, and sections may have been replaced.
+func dwarfcompress(ctxt *Link) {
+ if !ctxt.IsELF || ctxt.LinkMode == LinkExternal {
+ return
+ }
+
+ var start int
+ var newDwarfp []*sym.Symbol
+ Segdwarf.Sections = Segdwarf.Sections[:0]
+ for i, s := range dwarfp {
+ // Find the boundaries between sections and compress
+ // the whole section once we've found the last of its
+ // symbols.
+ if i+1 >= len(dwarfp) || s.Sect != dwarfp[i+1].Sect {
+ s1 := compressSyms(ctxt, dwarfp[start:i+1])
+ if s1 == nil {
+ // Compression didn't help.
+ newDwarfp = append(newDwarfp, dwarfp[start:i+1]...)
+ Segdwarf.Sections = append(Segdwarf.Sections, s.Sect)
+ } else {
+ compressedSegName := ".zdebug_" + s.Sect.Name[len(".debug_"):]
+ sect := addsection(ctxt.Arch, &Segdwarf, compressedSegName, 04)
+ sect.Length = uint64(len(s1))
+ newSym := ctxt.Syms.Lookup(compressedSegName, 0)
+ newSym.P = s1
+ newSym.Size = int64(len(s1))
+ newSym.Sect = sect
+ newDwarfp = append(newDwarfp, newSym)
+ }
+ start = i + 1
+ }
+ }
+ dwarfp = newDwarfp
+
+ // Re-compute the locations of the compressed DWARF symbols
+ // and sections, since the layout of these within the file is
+ // based on Section.Vaddr and Symbol.Value.
+ pos := Segdwarf.Vaddr
+ var prevSect *sym.Section
+ for _, s := range dwarfp {
+ s.Value = int64(pos)
+ if s.Sect != prevSect {
+ s.Sect.Vaddr = uint64(s.Value)
+ prevSect = s.Sect
+ }
+ if s.Sub != nil {
+ log.Fatalf("%s: unexpected sub-symbols", s)
+ }
+ pos += uint64(s.Size)
+ }
+ Segdwarf.Length = pos - Segdwarf.Vaddr
+}