]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: separate virtual address layout from file layout
authorAustin Clements <austin@google.com>
Fri, 4 May 2018 18:55:31 +0000 (14:55 -0400)
committerAustin Clements <austin@google.com>
Fri, 15 Jun 2018 02:01:04 +0000 (02:01 +0000)
Currently these two forms of layout are done in a single pass. This
makes it difficult to compress DWARF sections because that must be
done after relocations are applied, which must happen after virtual
address layout, but we can't layout the file until we've compressed
the DWARF sections.

Fix this by separating the two layout steps. In the process, we can
also unify the copy-pasted code in Link.address to compute file
offsets, which currently has some unnecessary variation.

Unlike the current file offset computation, which depends on virtual
addresses, the new computation only uses file offsets and sizes. This
will let us compress the file representation of a segment and create
the file layout based on its on-disk size rather than its original
in-memory size.

Tested by comparing the test binary for the "strings" package on all
supported GOOS/GOARCH combinations. All binaries are identical
(except, of course, their build IDs).

This is a second attempt at CL 111682.

For #11799.
Fixes #25863.

Change-Id: If09f28771bb4d78dd392fd58b8d7c9d5f22b0b9e
Reviewed-on: https://go-review.googlesource.com/118716
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/main.go

index 3e4773102d3704871bdd3d1573ae0881f3cac1de..e3587345263f6b6666c683a7de1523425201870d 100644 (file)
@@ -1903,12 +1903,15 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint6
        return sect, n, va
 }
 
-// assign addresses
-func (ctxt *Link) address() {
+// address assigns virtual addresses to all segments and sections and
+// returns all segments in file order.
+func (ctxt *Link) address() []*sym.Segment {
+       var order []*sym.Segment // Layout order
+
        va := uint64(*FlagTextAddr)
+       order = append(order, &Segtext)
        Segtext.Rwx = 05
        Segtext.Vaddr = va
-       Segtext.Fileoff = uint64(HEADR)
        for _, s := range Segtext.Sections {
                va = uint64(Rnd(int64(va), int64(s.Align)))
                s.Vaddr = va
@@ -1916,7 +1919,6 @@ func (ctxt *Link) address() {
        }
 
        Segtext.Length = va - uint64(*FlagTextAddr)
-       Segtext.Filelen = Segtext.Length
        if ctxt.HeadType == objabi.Hnacl {
                va += 32 // room for the "halt sled"
        }
@@ -1937,13 +1939,9 @@ func (ctxt *Link) address() {
                // writable even for this short period.
                va = uint64(Rnd(int64(va), int64(*FlagRound)))
 
+               order = append(order, &Segrodata)
                Segrodata.Rwx = 04
                Segrodata.Vaddr = va
-               Segrodata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
-               Segrodata.Filelen = 0
-               if ctxt.HeadType == objabi.Hwindows {
-                       Segrodata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN))
-               }
                for _, s := range Segrodata.Sections {
                        va = uint64(Rnd(int64(va), int64(s.Align)))
                        s.Vaddr = va
@@ -1951,17 +1949,15 @@ func (ctxt *Link) address() {
                }
 
                Segrodata.Length = va - Segrodata.Vaddr
-               Segrodata.Filelen = Segrodata.Length
        }
        if len(Segrelrodata.Sections) > 0 {
                // align to page boundary so as not to mix
                // rodata, rel-ro data, and executable text.
                va = uint64(Rnd(int64(va), int64(*FlagRound)))
 
+               order = append(order, &Segrelrodata)
                Segrelrodata.Rwx = 06
                Segrelrodata.Vaddr = va
-               Segrelrodata.Fileoff = va - Segrodata.Vaddr + Segrodata.Fileoff
-               Segrelrodata.Filelen = 0
                for _, s := range Segrelrodata.Sections {
                        va = uint64(Rnd(int64(va), int64(s.Align)))
                        s.Vaddr = va
@@ -1969,20 +1965,12 @@ func (ctxt *Link) address() {
                }
 
                Segrelrodata.Length = va - Segrelrodata.Vaddr
-               Segrelrodata.Filelen = Segrelrodata.Length
        }
 
        va = uint64(Rnd(int64(va), int64(*FlagRound)))
+       order = append(order, &Segdata)
        Segdata.Rwx = 06
        Segdata.Vaddr = va
-       Segdata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
-       Segdata.Filelen = 0
-       if ctxt.HeadType == objabi.Hwindows {
-               Segdata.Fileoff = Segrodata.Fileoff + uint64(Rnd(int64(Segrodata.Length), PEFILEALIGN))
-       }
-       if ctxt.HeadType == objabi.Hplan9 {
-               Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen
-       }
        var data *sym.Section
        var noptr *sym.Section
        var bss *sym.Section
@@ -2012,16 +2000,14 @@ func (ctxt *Link) address() {
                }
        }
 
+       // Assign Segdata's Filelen omitting the BSS. We do this here
+       // simply because right now we know where the BSS starts.
        Segdata.Filelen = bss.Vaddr - Segdata.Vaddr
 
        va = uint64(Rnd(int64(va), int64(*FlagRound)))
+       order = append(order, &Segdwarf)
        Segdwarf.Rwx = 06
        Segdwarf.Vaddr = va
-       Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(*FlagRound)))
-       Segdwarf.Filelen = 0
-       if ctxt.HeadType == objabi.Hwindows {
-               Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), PEFILEALIGN))
-       }
        for i, s := range Segdwarf.Sections {
                vlen := int64(s.Length)
                if i+1 < len(Segdwarf.Sections) {
@@ -2035,8 +2021,6 @@ func (ctxt *Link) address() {
                Segdwarf.Length = va - Segdwarf.Vaddr
        }
 
-       Segdwarf.Filelen = va - Segdwarf.Vaddr
-
        var (
                text     = Segtext.Sections[0]
                rodata   = ctxt.Syms.Lookup("runtime.rodata", 0).Sect
@@ -2123,6 +2107,41 @@ func (ctxt *Link) address() {
        ctxt.xdefine("runtime.noptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr))
        ctxt.xdefine("runtime.enoptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
        ctxt.xdefine("runtime.end", sym.SBSS, int64(Segdata.Vaddr+Segdata.Length))
+
+       return order
+}
+
+// layout assigns file offsets and lengths to the segments in order.
+func (ctxt *Link) layout(order []*sym.Segment) {
+       var prev *sym.Segment
+       for _, seg := range order {
+               if prev == nil {
+                       seg.Fileoff = uint64(HEADR)
+               } else {
+                       switch ctxt.HeadType {
+                       default:
+                               // Assuming the previous segment was
+                               // aligned, the following rounding
+                               // should ensure that this segment's
+                               // VA ≡ Fileoff mod FlagRound.
+                               seg.Fileoff = uint64(Rnd(int64(prev.Fileoff+prev.Filelen), int64(*FlagRound)))
+                               if seg.Vaddr%uint64(*FlagRound) != seg.Fileoff%uint64(*FlagRound) {
+                                       Exitf("bad segment rounding (Vaddr=%#x Fileoff=%#x FlagRound=%#x)", seg.Vaddr, seg.Fileoff, *FlagRound)
+                               }
+                       case objabi.Hwindows:
+                               seg.Fileoff = prev.Fileoff + uint64(Rnd(int64(prev.Filelen), PEFILEALIGN))
+                       case objabi.Hplan9:
+                               seg.Fileoff = prev.Fileoff + prev.Filelen
+                       }
+               }
+               if seg != &Segdata {
+                       // Link.address already set Segdata.Filelen to
+                       // account for BSS.
+                       seg.Filelen = seg.Length
+               }
+               prev = seg
+       }
+
 }
 
 // add a trampoline with symbol s (to be laid down after the current function)
index bfa3f70a9eefa458d6c7e275c0720efe7fddb4fd..23dfa277d0eaa5fe37980c127a011f2e1e60886b 100644 (file)
@@ -224,8 +224,9 @@ func Main(arch *sys.Arch, theArch Arch) {
        ctxt.typelink()
        ctxt.symtab()
        ctxt.dodata()
-       ctxt.address()
+       order := ctxt.address()
        ctxt.reloc()
+       ctxt.layout(order)
        thearch.Asmb(ctxt)
        ctxt.undef()
        ctxt.hostlink()