github.com/eh-steve/goloader@v0.0.0-20240111193454-90ff3cfdae39/init.1.21.go (about)

     1  //go:build go1.21 && !go1.23
     2  // +build go1.21,!go1.23
     3  
     4  package goloader
     5  
     6  import (
     7  	"cmd/objfile/objabi"
     8  	"slices"
     9  	"sort"
    10  	"strings"
    11  	"unsafe"
    12  )
    13  
    14  const (
    15  	_InitTaskSuffix = "..inittask"
    16  )
    17  
    18  func getInitFuncName(packagename string) string {
    19  	return objabi.PathToPrefix(packagename) + _InitTaskSuffix
    20  }
    21  
    22  // doInit1 is defined in package runtime
    23  //
    24  //go:linkname doInit1 runtime.doInit1
    25  func doInit1(t unsafe.Pointer) // t should be a *runtime.initTask
    26  
    27  type initTask struct {
    28  	state uint32 // 0 = uninitialized, 1 = in progress, 2 = done
    29  	nfns  uint32
    30  	// followed by nfns pcs, uintptr sized, one per init function to run
    31  }
    32  
    33  func (linker *Linker) doInitialize(codeModule *CodeModule, symbolMap map[string]uintptr) error {
    34  	// Autolib order is not necessarily the same as the  (*Link).inittaskSym algorithm in cmd/link/internal/ld/inittask.go,
    35  	// but it works and avoids a Kahn's graph traversal of R_INITORDER relocs...
    36  	autolibOrder := linker.Autolib()
    37  	for i := range autolibOrder {
    38  		// ..inittask symbol names will have their package escaped, so autolib list needs to as well
    39  		autolibOrder[i] = objabi.PathToPrefix(autolibOrder[i])
    40  	}
    41  	sort.Slice(linker.initFuncs, func(i, j int) bool {
    42  		return slices.Index(autolibOrder, strings.TrimSuffix(linker.initFuncs[i], _InitTaskSuffix)) < slices.Index(autolibOrder, strings.TrimSuffix(linker.initFuncs[j], _InitTaskSuffix))
    43  	})
    44  	for _, name := range linker.initFuncs {
    45  		if taskPtr, ok := symbolMap[name]; ok && taskPtr != 0 { // taskPtr may be nil if the inittask wasn't seen in the host symtab (probably a no-op and therefore eliminated)
    46  			shouldSkipDedup := false
    47  			for _, pkgPath := range linker.options.SkipTypeDeduplicationForPackages {
    48  				if strings.HasPrefix(name, pkgPath) {
    49  					shouldSkipDedup = true
    50  				}
    51  			}
    52  			x := (*initTask)(unsafe.Pointer(taskPtr))
    53  			if shouldSkipDedup {
    54  				x.state = 0 // Reset the inittask state in order to rerun the init function for the new version of the package
    55  			}
    56  			if x.nfns == 0 {
    57  				// Linker is expected to have stripped inittasks with no funcs
    58  				continue
    59  			}
    60  			doInit1(adduintptr(taskPtr, 0))
    61  		}
    62  	}
    63  	return nil
    64  }