github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/loader/loader_latest.go (about)

     1  //go:build go1.16 && !go1.22
     2  // +build go1.16,!go1.22
     3  
     4  /*
     5   * Copyright 2021 ByteDance Inc.
     6   *
     7   * Licensed under the Apache License, Version 2.0 (the "License");
     8   * you may not use this file except in compliance with the License.
     9   * You may obtain a copy of the License at
    10   *
    11   *     http://www.apache.org/licenses/LICENSE-2.0
    12   *
    13   * Unless required by applicable law or agreed to in writing, software
    14   * distributed under the License is distributed on an "AS IS" BASIS,
    15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16   * See the License for the specific language governing permissions and
    17   * limitations under the License.
    18   */
    19  
    20  package loader
    21  
    22  import (
    23  	"github.com/goshafaq/sonic/internal/rt"
    24  )
    25  
    26  // LoadFuncs loads only one function as module, and returns the function pointer
    27  //   - text: machine code
    28  //   - funcName: function name
    29  //   - frameSize: stack frame size.
    30  //   - argSize: argument total size (in bytes)
    31  //   - argPtrs: indicates if a slot (8 Bytes) of arguments memory stores pointer, from low to high
    32  //   - localPtrs: indicates if a slot (8 Bytes) of local variants memory stores pointer, from low to high
    33  //
    34  // WARN:
    35  //   - the function MUST has fixed SP offset equaling to this, otherwise it go.gentraceback will fail
    36  //   - the function MUST has only one stack map for all arguments and local variants
    37  func (self Loader) LoadOne(text []byte, funcName string, frameSize int, argSize int, argPtrs []bool, localPtrs []bool) Function {
    38  	size := uint32(len(text))
    39  
    40  	fn := Func{
    41  		Name:     funcName,
    42  		TextSize: size,
    43  		ArgsSize: int32(argSize),
    44  	}
    45  
    46  	// NOTICE: suppose the function has fixed SP offset equaling to frameSize, thus make only one pcsp pair
    47  	fn.Pcsp = &Pcdata{
    48  		{PC: size, Val: int32(frameSize)},
    49  	}
    50  
    51  	if self.NoPreempt {
    52  		fn.PcUnsafePoint = &Pcdata{
    53  			{PC: size, Val: PCDATA_UnsafePointUnsafe},
    54  		}
    55  	} else {
    56  		fn.PcUnsafePoint = &Pcdata{
    57  			{PC: size, Val: PCDATA_UnsafePointSafe},
    58  		}
    59  	}
    60  
    61  	// NOTICE: suppose the function has only one stack map at index 0
    62  	fn.PcStackMapIndex = &Pcdata{
    63  		{PC: size, Val: 0},
    64  	}
    65  
    66  	if argPtrs != nil {
    67  		args := rt.StackMapBuilder{}
    68  		for _, b := range argPtrs {
    69  			args.AddField(b)
    70  		}
    71  		fn.ArgsPointerMaps = args.Build()
    72  	}
    73  
    74  	if localPtrs != nil {
    75  		locals := rt.StackMapBuilder{}
    76  		for _, b := range localPtrs {
    77  			locals.AddField(b)
    78  		}
    79  		fn.LocalsPointerMaps = locals.Build()
    80  	}
    81  
    82  	out := Load(text, []Func{fn}, self.Name+funcName, []string{self.File})
    83  	return out[0]
    84  }
    85  
    86  // Load loads given machine codes and corresponding function information into go moduledata
    87  // and returns runnable function pointer
    88  // WARN: this API is experimental, use it carefully
    89  func Load(text []byte, funcs []Func, modulename string, filenames []string) (out []Function) {
    90  	ids := make([]string, len(funcs))
    91  	for i, f := range funcs {
    92  		ids[i] = f.Name
    93  	}
    94  	// generate module data and allocate memory address
    95  	mod := makeModuledata(modulename, filenames, &funcs, text)
    96  
    97  	// verify and register the new module
    98  	moduledataverify1(mod)
    99  	registerModule(mod)
   100  
   101  	//
   102  	// encapsulate function address
   103  	out = make([]Function, len(funcs))
   104  	for i, s := range ids {
   105  		for _, f := range funcs {
   106  			if f.Name == s {
   107  				m := uintptr(mod.text + uintptr(f.EntryOff))
   108  				out[i] = Function(&m)
   109  			}
   110  		}
   111  	}
   112  	return
   113  }