Source file src/cmd/link/internal/ld/seh.go

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ld
     6  
     7  import (
     8  	"cmd/internal/sys"
     9  	"cmd/link/internal/loader"
    10  	"cmd/link/internal/sym"
    11  )
    12  
    13  var sehp struct {
    14  	pdata []sym.LoaderSym
    15  	xdata []sym.LoaderSym
    16  }
    17  
    18  func writeSEH(ctxt *Link) {
    19  	switch ctxt.Arch.Family {
    20  	case sys.AMD64:
    21  		writeSEHAMD64(ctxt)
    22  	}
    23  }
    24  
    25  func writeSEHAMD64(ctxt *Link) {
    26  	ldr := ctxt.loader
    27  	mkSecSym := func(name string, kind sym.SymKind) *loader.SymbolBuilder {
    28  		s := ldr.CreateSymForUpdate(name, 0)
    29  		s.SetType(kind)
    30  		s.SetAlign(4)
    31  		return s
    32  	}
    33  	pdata := mkSecSym(".pdata", sym.SSEHSECT)
    34  	xdata := mkSecSym(".xdata", sym.SSEHSECT)
    35  	// The .xdata entries have very low cardinality
    36  	// as it only contains frame pointer operations,
    37  	// which are very similar across functions.
    38  	// These are referenced by .pdata entries using
    39  	// an RVA, so it is possible, and binary-size wise,
    40  	// to deduplicate .xdata entries.
    41  	uwcache := make(map[string]int64) // aux symbol name --> .xdata offset
    42  	for _, s := range ctxt.Textp {
    43  		if fi := ldr.FuncInfo(s); !fi.Valid() {
    44  			continue
    45  		}
    46  		uw := ldr.SEHUnwindSym(s)
    47  		if uw == 0 {
    48  			continue
    49  		}
    50  		name := ctxt.SymName(uw)
    51  		off, cached := uwcache[name]
    52  		if !cached {
    53  			off = xdata.Size()
    54  			uwcache[name] = off
    55  			xdata.AddBytes(ldr.Data(uw))
    56  			// The SEH unwind data can contain relocations,
    57  			// make sure those are copied over.
    58  			rels := ldr.Relocs(uw)
    59  			for i := 0; i < rels.Count(); i++ {
    60  				r := rels.At(i)
    61  				rel, _ := xdata.AddRel(r.Type())
    62  				rel.SetOff(int32(off) + r.Off())
    63  				rel.SetSiz(r.Siz())
    64  				rel.SetSym(r.Sym())
    65  				rel.SetAdd(r.Add())
    66  			}
    67  		}
    68  
    69  		// Reference:
    70  		// https://learn.microsoft.com/en-us/cpp/build/exception-handling-x64#struct-runtime_function
    71  		pdata.AddPEImageRelativeAddrPlus(ctxt.Arch, s, 0)
    72  		pdata.AddPEImageRelativeAddrPlus(ctxt.Arch, s, ldr.SymSize(s))
    73  		pdata.AddPEImageRelativeAddrPlus(ctxt.Arch, xdata.Sym(), off)
    74  	}
    75  	sehp.pdata = append(sehp.pdata, pdata.Sym())
    76  	sehp.xdata = append(sehp.xdata, xdata.Sym())
    77  }
    78  

View as plain text