545 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			545 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| //go:build go1.20 && !go1.21
 | |
| // +build go1.20,!go1.21
 | |
| 
 | |
| /*
 | |
|  * Copyright 2021 ByteDance Inc.
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| package loader
 | |
| 
 | |
| import (
 | |
|     `encoding`
 | |
|     `os`
 | |
|     `unsafe`
 | |
| 
 | |
|     `github.com/bytedance/sonic/internal/rt`
 | |
| )
 | |
| 
 | |
| const (
 | |
|     _Magic uint32 = 0xFFFFFFF1
 | |
| )
 | |
| 
 | |
| type moduledata struct {
 | |
|     pcHeader     *pcHeader
 | |
|     funcnametab  []byte
 | |
|     cutab        []uint32
 | |
|     filetab      []byte
 | |
|     pctab        []byte
 | |
|     pclntable    []byte
 | |
|     ftab         []funcTab
 | |
|     findfunctab  uintptr
 | |
|     minpc, maxpc uintptr // first func address, last func address + last func size
 | |
| 
 | |
|     text, etext           uintptr // start/end of text, (etext-text) must be greater than MIN_FUNC
 | |
|     noptrdata, enoptrdata uintptr
 | |
|     data, edata           uintptr
 | |
|     bss, ebss             uintptr
 | |
|     noptrbss, enoptrbss   uintptr
 | |
|     covctrs, ecovctrs     uintptr
 | |
|     end, gcdata, gcbss    uintptr
 | |
|     types, etypes         uintptr
 | |
|     rodata                uintptr
 | |
| 
 | |
|     // TODO: generate funcinfo object to memory
 | |
|     gofunc                uintptr // go.func.* is actual funcinfo object in image
 | |
| 
 | |
|     textsectmap []textSection // see runtime/symtab.go: textAddr()
 | |
|     typelinks   []int32 // offsets from types
 | |
|     itablinks   []*rt.GoItab
 | |
| 
 | |
|     ptab []ptabEntry
 | |
| 
 | |
|     pluginpath string
 | |
|     pkghashes  []modulehash
 | |
| 
 | |
|     modulename   string
 | |
|     modulehashes []modulehash
 | |
| 
 | |
|     hasmain uint8 // 1 if module contains the main function, 0 otherwise
 | |
| 
 | |
|     gcdatamask, gcbssmask bitVector
 | |
| 
 | |
|     typemap map[int32]*rt.GoType // offset to *_rtype in previous module
 | |
| 
 | |
|     bad bool // module failed to load and should be ignored
 | |
| 
 | |
|     next *moduledata
 | |
| }
 | |
| 
 | |
| type _func struct {
 | |
|     entryOff uint32 // start pc, as offset from moduledata.text/pcHeader.textStart
 | |
|     nameOff  int32  // function name, as index into moduledata.funcnametab.
 | |
| 
 | |
|     args        int32  // in/out args size
 | |
|     deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
 | |
| 
 | |
|     pcsp      uint32 
 | |
|     pcfile    uint32
 | |
|     pcln      uint32
 | |
|     npcdata   uint32
 | |
|     cuOffset  uint32 // runtime.cutab offset of this function's CU
 | |
|     startLine int32  // line number of start of function (func keyword/TEXT directive)
 | |
|     funcID    uint8 // set for certain special runtime functions
 | |
|     flag      uint8
 | |
|     _         [1]byte // pad
 | |
|     nfuncdata uint8   // 
 | |
|     
 | |
|     // The end of the struct is followed immediately by two variable-length
 | |
|     // arrays that reference the pcdata and funcdata locations for this
 | |
|     // function.
 | |
| 
 | |
|     // pcdata contains the offset into moduledata.pctab for the start of
 | |
|     // that index's table. e.g.,
 | |
|     // &moduledata.pctab[_func.pcdata[_PCDATA_UnsafePoint]] is the start of
 | |
|     // the unsafe point table.
 | |
|     //
 | |
|     // An offset of 0 indicates that there is no table.
 | |
|     //
 | |
|     // pcdata [npcdata]uint32
 | |
| 
 | |
|     // funcdata contains the offset past moduledata.gofunc which contains a
 | |
|     // pointer to that index's funcdata. e.g.,
 | |
|     // *(moduledata.gofunc +  _func.funcdata[_FUNCDATA_ArgsPointerMaps]) is
 | |
|     // the argument pointer map.
 | |
|     //
 | |
|     // An offset of ^uint32(0) indicates that there is no entry.
 | |
|     //
 | |
|     // funcdata [nfuncdata]uint32
 | |
| }
 | |
| 
 | |
| type funcTab struct {
 | |
|     entry   uint32
 | |
|     funcoff uint32
 | |
| }
 | |
| 
 | |
| type pcHeader struct {
 | |
|     magic          uint32  // 0xFFFFFFF0
 | |
|     pad1, pad2     uint8   // 0,0
 | |
|     minLC          uint8   // min instruction size
 | |
|     ptrSize        uint8   // size of a ptr in bytes
 | |
|     nfunc          int     // number of functions in the module
 | |
|     nfiles         uint    // number of entries in the file tab
 | |
|     textStart      uintptr // base for function entry PC offsets in this module, equal to moduledata.text
 | |
|     funcnameOffset uintptr // offset to the funcnametab variable from pcHeader
 | |
|     cuOffset       uintptr // offset to the cutab variable from pcHeader
 | |
|     filetabOffset  uintptr // offset to the filetab variable from pcHeader
 | |
|     pctabOffset    uintptr // offset to the pctab variable from pcHeader
 | |
|     pclnOffset     uintptr // offset to the pclntab variable from pcHeader
 | |
| }
 | |
| 
 | |
| type bitVector struct {
 | |
|     n        int32 // # of bits
 | |
|     bytedata *uint8
 | |
| }
 | |
| 
 | |
| type ptabEntry struct {
 | |
|     name int32
 | |
|     typ  int32
 | |
| }
 | |
| 
 | |
| type textSection struct {
 | |
|     vaddr    uintptr // prelinked section vaddr
 | |
|     end      uintptr // vaddr + section length
 | |
|     baseaddr uintptr // relocated section address
 | |
| }
 | |
| 
 | |
| type modulehash struct {
 | |
|     modulename   string
 | |
|     linktimehash string
 | |
|     runtimehash  *string
 | |
| }
 | |
| 
 | |
| // findfuncbucket is an array of these structures.
 | |
| // Each bucket represents 4096 bytes of the text segment.
 | |
| // Each subbucket represents 256 bytes of the text segment.
 | |
| // To find a function given a pc, locate the bucket and subbucket for
 | |
| // that pc. Add together the idx and subbucket value to obtain a
 | |
| // function index. Then scan the functab array starting at that
 | |
| // index to find the target function.
 | |
| // This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
 | |
| type findfuncbucket struct {
 | |
|     idx        uint32
 | |
|     _SUBBUCKETS [16]byte
 | |
| }
 | |
| 
 | |
| // func name table format: 
 | |
| //   nameOff[0] -> namePartA namePartB namePartC \x00 
 | |
| //   nameOff[1] -> namePartA namePartB namePartC \x00
 | |
| //  ...
 | |
| func makeFuncnameTab(funcs []Func) (tab []byte, offs []int32) {
 | |
|     offs = make([]int32, len(funcs))
 | |
|     offset := 0
 | |
| 
 | |
|     for i, f := range funcs {
 | |
|         offs[i] = int32(offset)
 | |
| 
 | |
|         a, b, c := funcNameParts(f.Name)
 | |
|         tab = append(tab, a...)
 | |
|         tab = append(tab, b...)
 | |
|         tab = append(tab, c...)
 | |
|         tab = append(tab, 0)
 | |
|         offset += len(a) + len(b) + len(c) + 1
 | |
|     }
 | |
| 
 | |
|     return
 | |
| }
 | |
| 
 | |
| type compilationUnit struct {
 | |
|     fileNames []string
 | |
| }
 | |
| 
 | |
| // CU table format:
 | |
| //  cuOffsets[0] -> filetabOffset[0] filetabOffset[1] ... filetabOffset[len(CUs[0].fileNames)-1]
 | |
| //  cuOffsets[1] -> filetabOffset[len(CUs[0].fileNames)] ... filetabOffset[len(CUs[0].fileNames) + len(CUs[1].fileNames)-1]
 | |
| //  ...
 | |
| //
 | |
| // file name table format:
 | |
| //  filetabOffset[0] -> CUs[0].fileNames[0] \x00
 | |
| //  ...
 | |
| //  filetabOffset[len(CUs[0]-1)] -> CUs[0].fileNames[len(CUs[0].fileNames)-1] \x00
 | |
| //  ...
 | |
| //  filetabOffset[SUM(CUs,fileNames)-1] -> CUs[len(CU)-1].fileNames[len(CUs[len(CU)-1].fileNames)-1] \x00
 | |
| func makeFilenametab(cus []compilationUnit) (cutab []uint32, filetab []byte, cuOffsets []uint32) {
 | |
|     cuOffsets = make([]uint32, len(cus))
 | |
|     cuOffset := 0
 | |
|     fileOffset := 0
 | |
| 
 | |
|     for i, cu := range cus {
 | |
|         cuOffsets[i] = uint32(cuOffset)
 | |
| 
 | |
|         for _, name := range cu.fileNames {
 | |
|             cutab = append(cutab, uint32(fileOffset))
 | |
| 
 | |
|             fileOffset += len(name) + 1
 | |
|             filetab = append(filetab, name...)
 | |
|             filetab = append(filetab, 0)
 | |
|         }
 | |
| 
 | |
|         cuOffset += len(cu.fileNames)
 | |
|     }
 | |
| 
 | |
|     return
 | |
| }
 | |
| 
 | |
| func writeFuncdata(out *[]byte, funcs []Func) (fstart int, funcdataOffs [][]uint32) {
 | |
|     fstart = len(*out)
 | |
|     *out = append(*out, byte(0))
 | |
|     offs := uint32(1)
 | |
| 
 | |
|     funcdataOffs = make([][]uint32, len(funcs))
 | |
|     for i, f := range funcs {
 | |
| 
 | |
|         var writer = func(fd encoding.BinaryMarshaler) {
 | |
|             var ab []byte
 | |
|             var err error
 | |
|             if fd != nil {
 | |
|                 ab, err = fd.MarshalBinary()
 | |
|                 if err != nil {
 | |
|                     panic(err)
 | |
|                 }
 | |
|                 funcdataOffs[i] = append(funcdataOffs[i], offs)
 | |
|             } else {
 | |
|                 ab = []byte{0}
 | |
|                 funcdataOffs[i] = append(funcdataOffs[i], _INVALID_FUNCDATA_OFFSET)
 | |
|             }
 | |
|             *out = append(*out, ab...)
 | |
|             offs += uint32(len(ab))
 | |
|         }
 | |
| 
 | |
|         writer(f.ArgsPointerMaps)
 | |
|         writer(f.LocalsPointerMaps)
 | |
|         writer(f.StackObjects)
 | |
|         writer(f.InlTree)
 | |
|         writer(f.OpenCodedDeferInfo)
 | |
|         writer(f.ArgInfo)
 | |
|         writer(f.ArgLiveInfo)
 | |
|         writer(f.WrapInfo)
 | |
|     }
 | |
|     return 
 | |
| }
 | |
| 
 | |
| func makeFtab(funcs []_func, lastFuncSize uint32) (ftab []funcTab) {
 | |
|     // Allocate space for the pc->func table. This structure consists of a pc offset
 | |
|     // and an offset to the func structure. After that, we have a single pc
 | |
|     // value that marks the end of the last function in the binary.
 | |
|     var size int64 = int64(len(funcs)*2*4 + 4)
 | |
|     var startLocations = make([]uint32, len(funcs))
 | |
|     for i, f := range funcs {
 | |
|         size = rnd(size, int64(_PtrSize))
 | |
|         //writePCToFunc
 | |
|         startLocations[i] = uint32(size)
 | |
|         size += int64(uint8(_FUNC_SIZE)+f.nfuncdata*4+uint8(f.npcdata)*4)
 | |
|     }
 | |
| 
 | |
|     ftab = make([]funcTab, 0, len(funcs)+1)
 | |
| 
 | |
|     // write a map of pc->func info offsets 
 | |
|     for i, f := range funcs {
 | |
|         ftab = append(ftab, funcTab{uint32(f.entryOff), uint32(startLocations[i])})
 | |
|     }
 | |
| 
 | |
|     // Final entry of table is just end pc offset.
 | |
|     lastFunc := funcs[len(funcs)-1]
 | |
|     ftab = append(ftab, funcTab{uint32(lastFunc.entryOff + lastFuncSize), 0})
 | |
| 
 | |
|     return
 | |
| }
 | |
| 
 | |
| // Pcln table format: [...]funcTab + [...]_Func
 | |
| func makePclntable(funcs []_func, lastFuncSize uint32, pcdataOffs [][]uint32, funcdataOffs [][]uint32) (pclntab []byte) {
 | |
|     // Allocate space for the pc->func table. This structure consists of a pc offset
 | |
|     // and an offset to the func structure. After that, we have a single pc
 | |
|     // value that marks the end of the last function in the binary.
 | |
|     var size int64 = int64(len(funcs)*2*4 + 4)
 | |
|     var startLocations = make([]uint32, len(funcs))
 | |
|     for i := range funcs {
 | |
|         size = rnd(size, int64(_PtrSize))
 | |
|         //writePCToFunc
 | |
|         startLocations[i] = uint32(size)
 | |
|         size += int64(int(_FUNC_SIZE)+len(funcdataOffs[i])*4+len(pcdataOffs[i])*4)
 | |
|     }
 | |
| 
 | |
|     pclntab = make([]byte, size, size)
 | |
| 
 | |
|     // write a map of pc->func info offsets 
 | |
|     offs := 0
 | |
|     for i, f := range funcs {
 | |
|         byteOrder.PutUint32(pclntab[offs:offs+4], uint32(f.entryOff))
 | |
|         byteOrder.PutUint32(pclntab[offs+4:offs+8], uint32(startLocations[i]))
 | |
|         offs += 8
 | |
|     }
 | |
|     // Final entry of table is just end pc offset.
 | |
|     lastFunc := funcs[len(funcs)-1]
 | |
|     byteOrder.PutUint32(pclntab[offs:offs+4], uint32(lastFunc.entryOff+lastFuncSize))
 | |
| 
 | |
|     // write func info table
 | |
|     for i, f := range funcs {
 | |
|         off := startLocations[i]
 | |
| 
 | |
|         // write _func structure to pclntab
 | |
|         fb := rt.BytesFrom(unsafe.Pointer(&f), int(_FUNC_SIZE), int(_FUNC_SIZE))
 | |
|         copy(pclntab[off:off+uint32(_FUNC_SIZE)], fb)
 | |
|         off += uint32(_FUNC_SIZE)
 | |
| 
 | |
|         // NOTICE: _func.pcdata always starts from PcUnsafePoint, which is index 3
 | |
|         for j := 3; j < len(pcdataOffs[i]); j++ {
 | |
|             byteOrder.PutUint32(pclntab[off:off+4], uint32(pcdataOffs[i][j]))
 | |
|             off += 4
 | |
|         }
 | |
| 
 | |
|         // funcdata refs as offsets from gofunc
 | |
|         for _, funcdata := range funcdataOffs[i] {
 | |
|             byteOrder.PutUint32(pclntab[off:off+4], uint32(funcdata))
 | |
|             off += 4
 | |
|         }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     return
 | |
| }
 | |
| 
 | |
| // findfunc table used to map pc to belonging func, 
 | |
| // returns the index in the func table.
 | |
| //
 | |
| // All text section are divided into buckets sized _BUCKETSIZE(4K):
 | |
| //   every bucket is divided into _SUBBUCKETS sized _SUB_BUCKETSIZE(64),
 | |
| //   and it has a base idx to plus the offset stored in jth subbucket.
 | |
| // see findfunc() in runtime/symtab.go
 | |
| func writeFindfunctab(out *[]byte, ftab []funcTab) (start int) {
 | |
|     start = len(*out)
 | |
| 
 | |
|     max := ftab[len(ftab)-1].entry
 | |
|     min := ftab[0].entry
 | |
|     nbuckets := (max - min + _BUCKETSIZE - 1) / _BUCKETSIZE
 | |
|     n := (max - min + _SUB_BUCKETSIZE - 1) / _SUB_BUCKETSIZE
 | |
| 
 | |
|     tab := make([]findfuncbucket, 0, nbuckets)
 | |
|     var s, e = 0, 0
 | |
|     for i := 0; i<int(nbuckets); i++ {
 | |
|         var pc = min + uint32((i+1)*_BUCKETSIZE)
 | |
|         // find the end func of the bucket
 | |
|         for ; e < len(ftab)-1 && ftab[e+1].entry <= pc; e++ {}
 | |
|         // store the start func of the bucket
 | |
|         var fb = findfuncbucket{idx: uint32(s)}
 | |
| 
 | |
|         for j := 0; j<_SUBBUCKETS && (i*_SUBBUCKETS+j)<int(n); j++ {
 | |
|             pc = min + uint32(i*_BUCKETSIZE) + uint32((j+1)*_SUB_BUCKETSIZE)
 | |
|             var ss = s
 | |
|             // find the end func of the subbucket
 | |
|             for ; ss < len(ftab)-1 && ftab[ss+1].entry <= pc; ss++ {}
 | |
|             // store the start func of the subbucket
 | |
|             fb._SUBBUCKETS[j] = byte(uint32(s) - fb.idx)
 | |
|             s = ss
 | |
|         }
 | |
|         s = e
 | |
|         tab = append(tab, fb)
 | |
|     }
 | |
| 
 | |
|     // write findfuncbucket
 | |
|     if len(tab) > 0 {
 | |
|         size := int(unsafe.Sizeof(findfuncbucket{}))*len(tab)
 | |
|         *out = append(*out, rt.BytesFrom(unsafe.Pointer(&tab[0]), size, size)...)
 | |
|     }
 | |
|     return 
 | |
| }
 | |
| 
 | |
| func makeModuledata(name string, filenames []string, funcs []Func, text []byte) (mod *moduledata) {
 | |
|     mod = new(moduledata)
 | |
|     mod.modulename = name
 | |
| 
 | |
|     // make filename table
 | |
|     cu := make([]string, 0, len(filenames))
 | |
|     for _, f := range filenames {
 | |
|         cu = append(cu, f)
 | |
|     }
 | |
|     cutab, filetab, cuOffs := makeFilenametab([]compilationUnit{{cu}})
 | |
|     mod.cutab = cutab
 | |
|     mod.filetab = filetab
 | |
| 
 | |
|     // make funcname table
 | |
|     funcnametab, nameOffs := makeFuncnameTab(funcs)
 | |
|     mod.funcnametab = funcnametab
 | |
| 
 | |
|     // make pcdata table
 | |
|     // NOTICE: _func only use offset to index pcdata, thus no need mmap() pcdata 
 | |
|     pctab, pcdataOffs, _funcs := makePctab(funcs, cuOffs, nameOffs)
 | |
|     mod.pctab = pctab
 | |
| 
 | |
|     // write func data
 | |
|     // NOTICE: _func use mod.gofunc+offset to directly point funcdata, thus need cache funcdata
 | |
|     // TODO: estimate accurate capacity
 | |
|     cache := make([]byte, 0, len(funcs)*int(_PtrSize)) 
 | |
|     fstart, funcdataOffs := writeFuncdata(&cache, funcs)
 | |
| 
 | |
|     // make pc->func (binary search) func table
 | |
|     lastFuncsize := funcs[len(funcs)-1].TextSize
 | |
|     ftab := makeFtab(_funcs, lastFuncsize)
 | |
|     mod.ftab = ftab
 | |
| 
 | |
|     // write pc->func (modmap) findfunc table
 | |
|     ffstart := writeFindfunctab(&cache, ftab)
 | |
| 
 | |
|     // make pclnt table
 | |
|     pclntab := makePclntable(_funcs, lastFuncsize, pcdataOffs, funcdataOffs)
 | |
|     mod.pclntable = pclntab
 | |
| 
 | |
|     // mmap() text and funcdata segements
 | |
|     p := os.Getpagesize()
 | |
|     size := int(rnd(int64(len(text)), int64(p)))
 | |
|     addr := mmap(size)
 | |
|     // copy the machine code
 | |
|     s := rt.BytesFrom(unsafe.Pointer(addr), len(text), size)
 | |
|     copy(s, text)
 | |
|     // make it executable
 | |
|     mprotect(addr, size)
 | |
| 
 | |
|     // assign addresses
 | |
|     mod.text = addr
 | |
|     mod.etext = addr + uintptr(size)
 | |
|     mod.minpc = addr
 | |
|     mod.maxpc = addr + uintptr(len(text))
 | |
| 
 | |
|     // cache funcdata and findfuncbucket
 | |
|     moduleCache.Lock()
 | |
|     moduleCache.m[mod] = cache
 | |
|     moduleCache.Unlock()
 | |
|     mod.gofunc = uintptr(unsafe.Pointer(&cache[fstart]))
 | |
|     mod.findfunctab = uintptr(unsafe.Pointer(&cache[ffstart]))
 | |
| 
 | |
|     // make pc header
 | |
|     mod.pcHeader = &pcHeader {
 | |
|         magic   : _Magic,
 | |
|         minLC   : _MinLC,
 | |
|         ptrSize : _PtrSize,
 | |
|         nfunc   : len(funcs),
 | |
|         nfiles: uint(len(cu)),
 | |
|         textStart: mod.text,
 | |
|         funcnameOffset: getOffsetOf(moduledata{}, "funcnametab"),
 | |
|         cuOffset: getOffsetOf(moduledata{}, "cutab"),
 | |
|         filetabOffset: getOffsetOf(moduledata{}, "filetab"),
 | |
|         pctabOffset: getOffsetOf(moduledata{}, "pctab"),
 | |
|         pclnOffset: getOffsetOf(moduledata{}, "pclntable"),
 | |
|     }
 | |
| 
 | |
|     // sepecial case: gcdata and gcbss must by non-empty
 | |
|     mod.gcdata = uintptr(unsafe.Pointer(&emptyByte))
 | |
|     mod.gcbss = uintptr(unsafe.Pointer(&emptyByte))
 | |
| 
 | |
|     return
 | |
| }
 | |
| 
 | |
| // makePctab generates pcdelta->valuedelta tables for functions,
 | |
| // and returns the table and the entry offset of every kind pcdata in the table.
 | |
| func makePctab(funcs []Func, cuOffset []uint32, nameOffset []int32) (pctab []byte, pcdataOffs [][]uint32, _funcs []_func) {
 | |
|     _funcs = make([]_func, len(funcs))
 | |
| 
 | |
|     // Pctab offsets of 0 are considered invalid in the runtime. We respect
 | |
|     // that by just padding a single byte at the beginning of runtime.pctab,
 | |
|     // that way no real offsets can be zero.
 | |
|     pctab = make([]byte, 1, 12*len(funcs)+1)
 | |
|     pcdataOffs = make([][]uint32, len(funcs))
 | |
| 
 | |
|     for i, f := range funcs {
 | |
|         _f := &_funcs[i]
 | |
| 
 | |
|         var writer = func(pc *Pcdata) {
 | |
|             var ab []byte
 | |
|             var err error
 | |
|             if pc != nil {
 | |
|                 ab, err = pc.MarshalBinary()
 | |
|                 if err != nil {
 | |
|                     panic(err)
 | |
|                 }
 | |
|                 pcdataOffs[i] = append(pcdataOffs[i], uint32(len(pctab)))
 | |
|             } else {
 | |
|                 ab = []byte{0}
 | |
|                 pcdataOffs[i] = append(pcdataOffs[i], _PCDATA_INVALID_OFFSET)
 | |
|             }
 | |
|             pctab = append(pctab, ab...)
 | |
|         }
 | |
| 
 | |
|         if f.Pcsp != nil {
 | |
|             _f.pcsp = uint32(len(pctab))
 | |
|         }
 | |
|         writer(f.Pcsp)
 | |
|         if f.Pcfile != nil {
 | |
|             _f.pcfile = uint32(len(pctab))
 | |
|         }
 | |
|         writer(f.Pcfile)
 | |
|         if f.Pcline != nil {
 | |
|             _f.pcln = uint32(len(pctab))
 | |
|         }
 | |
|         writer(f.Pcline)
 | |
|         writer(f.PcUnsafePoint)
 | |
|         writer(f.PcStackMapIndex)
 | |
|         writer(f.PcInlTreeIndex)
 | |
|         writer(f.PcArgLiveIndex)
 | |
|         
 | |
|         _f.entryOff = f.EntryOff
 | |
|         _f.nameOff = nameOffset[i]
 | |
|         _f.args = f.ArgsSize
 | |
|         _f.deferreturn = f.DeferReturn
 | |
|         // NOTICE: _func.pcdata is always as [PCDATA_UnsafePoint(0) : PCDATA_ArgLiveIndex(3)]
 | |
|         _f.npcdata = uint32(_N_PCDATA)
 | |
|         _f.cuOffset = cuOffset[i]
 | |
|         _f.funcID = f.ID
 | |
|         _f.flag = f.Flag
 | |
|         _f.nfuncdata = uint8(_N_FUNCDATA)
 | |
|     }
 | |
| 
 | |
|     return
 | |
| }
 | |
| 
 | |
| func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args int, size uintptr, argptrs uintptr, localptrs uintptr) {} |