Skip to content

Commit 8998c55

Browse files
committed
cmd/link: separate virtual address layout from file layout
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent c12399f commit 8998c55

File tree

2 files changed

+49
-29
lines changed

2 files changed

+49
-29
lines changed

src/cmd/link/internal/ld/data.go

Lines changed: 47 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1903,20 +1903,22 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint6
19031903
return sect, n, va
19041904
}
19051905

1906-
// assign addresses
1907-
func (ctxt *Link) address() {
1906+
// address assigns virtual addresses to all segments and sections and
1907+
// returns all segments in file order.
1908+
func (ctxt *Link) address() []*sym.Segment {
1909+
var order []*sym.Segment // Layout order
1910+
19081911
va := uint64(*FlagTextAddr)
1912+
order = append(order, &Segtext)
19091913
Segtext.Rwx = 05
19101914
Segtext.Vaddr = va
1911-
Segtext.Fileoff = uint64(HEADR)
19121915
for _, s := range Segtext.Sections {
19131916
va = uint64(Rnd(int64(va), int64(s.Align)))
19141917
s.Vaddr = va
19151918
va += s.Length
19161919
}
19171920

19181921
Segtext.Length = va - uint64(*FlagTextAddr)
1919-
Segtext.Filelen = Segtext.Length
19201922
if ctxt.HeadType == objabi.Hnacl {
19211923
va += 32 // room for the "halt sled"
19221924
}
@@ -1937,52 +1939,38 @@ func (ctxt *Link) address() {
19371939
// writable even for this short period.
19381940
va = uint64(Rnd(int64(va), int64(*FlagRound)))
19391941

1942+
order = append(order, &Segrodata)
19401943
Segrodata.Rwx = 04
19411944
Segrodata.Vaddr = va
1942-
Segrodata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
1943-
Segrodata.Filelen = 0
1944-
if ctxt.HeadType == objabi.Hwindows {
1945-
Segrodata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN))
1946-
}
19471945
for _, s := range Segrodata.Sections {
19481946
va = uint64(Rnd(int64(va), int64(s.Align)))
19491947
s.Vaddr = va
19501948
va += s.Length
19511949
}
19521950

19531951
Segrodata.Length = va - Segrodata.Vaddr
1954-
Segrodata.Filelen = Segrodata.Length
19551952
}
19561953
if len(Segrelrodata.Sections) > 0 {
19571954
// align to page boundary so as not to mix
19581955
// rodata, rel-ro data, and executable text.
19591956
va = uint64(Rnd(int64(va), int64(*FlagRound)))
19601957

1958+
order = append(order, &Segrelrodata)
19611959
Segrelrodata.Rwx = 06
19621960
Segrelrodata.Vaddr = va
1963-
Segrelrodata.Fileoff = va - Segrodata.Vaddr + Segrodata.Fileoff
1964-
Segrelrodata.Filelen = 0
19651961
for _, s := range Segrelrodata.Sections {
19661962
va = uint64(Rnd(int64(va), int64(s.Align)))
19671963
s.Vaddr = va
19681964
va += s.Length
19691965
}
19701966

19711967
Segrelrodata.Length = va - Segrelrodata.Vaddr
1972-
Segrelrodata.Filelen = Segrelrodata.Length
19731968
}
19741969

19751970
va = uint64(Rnd(int64(va), int64(*FlagRound)))
1971+
order = append(order, &Segdata)
19761972
Segdata.Rwx = 06
19771973
Segdata.Vaddr = va
1978-
Segdata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
1979-
Segdata.Filelen = 0
1980-
if ctxt.HeadType == objabi.Hwindows {
1981-
Segdata.Fileoff = Segrodata.Fileoff + uint64(Rnd(int64(Segrodata.Length), PEFILEALIGN))
1982-
}
1983-
if ctxt.HeadType == objabi.Hplan9 {
1984-
Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen
1985-
}
19861974
var data *sym.Section
19871975
var noptr *sym.Section
19881976
var bss *sym.Section
@@ -2012,16 +2000,14 @@ func (ctxt *Link) address() {
20122000
}
20132001
}
20142002

2003+
// Assign Segdata's Filelen omitting the BSS. We do this here
2004+
// simply because right now we know where the BSS starts.
20152005
Segdata.Filelen = bss.Vaddr - Segdata.Vaddr
20162006

20172007
va = uint64(Rnd(int64(va), int64(*FlagRound)))
2008+
order = append(order, &Segdwarf)
20182009
Segdwarf.Rwx = 06
20192010
Segdwarf.Vaddr = va
2020-
Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(*FlagRound)))
2021-
Segdwarf.Filelen = 0
2022-
if ctxt.HeadType == objabi.Hwindows {
2023-
Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), PEFILEALIGN))
2024-
}
20252011
for i, s := range Segdwarf.Sections {
20262012
vlen := int64(s.Length)
20272013
if i+1 < len(Segdwarf.Sections) {
@@ -2035,8 +2021,6 @@ func (ctxt *Link) address() {
20352021
Segdwarf.Length = va - Segdwarf.Vaddr
20362022
}
20372023

2038-
Segdwarf.Filelen = va - Segdwarf.Vaddr
2039-
20402024
var (
20412025
text = Segtext.Sections[0]
20422026
rodata = ctxt.Syms.Lookup("runtime.rodata", 0).Sect
@@ -2123,6 +2107,41 @@ func (ctxt *Link) address() {
21232107
ctxt.xdefine("runtime.noptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr))
21242108
ctxt.xdefine("runtime.enoptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
21252109
ctxt.xdefine("runtime.end", sym.SBSS, int64(Segdata.Vaddr+Segdata.Length))
2110+
2111+
return order
2112+
}
2113+
2114+
// layout assigns file offsets and lengths to the segments in order.
2115+
func (ctxt *Link) layout(order []*sym.Segment) {
2116+
var prev *sym.Segment
2117+
for _, seg := range order {
2118+
if prev == nil {
2119+
seg.Fileoff = uint64(HEADR)
2120+
} else {
2121+
switch ctxt.HeadType {
2122+
default:
2123+
// Assuming the previous segment was
2124+
// aligned, the following rounding
2125+
// should ensure that this segment's
2126+
// VA ≡ Fileoff mod FlagRound.
2127+
seg.Fileoff = uint64(Rnd(int64(prev.Fileoff+prev.Filelen), int64(*FlagRound)))
2128+
if seg.Vaddr%uint64(*FlagRound) != seg.Fileoff%uint64(*FlagRound) {
2129+
Exitf("bad segment rounding (Vaddr=%#x Fileoff=%#x FlagRound=%#x)", seg.Vaddr, seg.Fileoff, *FlagRound)
2130+
}
2131+
case objabi.Hwindows:
2132+
seg.Fileoff = prev.Fileoff + uint64(Rnd(int64(prev.Filelen), PEFILEALIGN))
2133+
case objabi.Hplan9:
2134+
seg.Fileoff = prev.Fileoff + prev.Filelen
2135+
}
2136+
}
2137+
if seg != &Segdata {
2138+
// Link.address already set Segdata.Filelen to
2139+
// account for BSS.
2140+
seg.Filelen = seg.Length
2141+
}
2142+
prev = seg
2143+
}
2144+
21262145
}
21272146

21282147
// add a trampoline with symbol s (to be laid down after the current function)

src/cmd/link/internal/ld/main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,9 @@ func Main(arch *sys.Arch, theArch Arch) {
224224
ctxt.typelink()
225225
ctxt.symtab()
226226
ctxt.dodata()
227-
ctxt.address()
227+
order := ctxt.address()
228228
ctxt.reloc()
229+
ctxt.layout(order)
229230
thearch.Asmb(ctxt)
230231
ctxt.undef()
231232
ctxt.hostlink()

0 commit comments

Comments
 (0)