github.com/pkujhd/goloader@v0.0.0-20240411034752-1a28096bd7bd/utils.go (about)

     1  package goloader
     2  
     3  import (
     4  	"cmd/objfile/sys"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"strconv"
     8  	"unsafe"
     9  
    10  	"github.com/pkujhd/goloader/mmap"
    11  	"github.com/pkujhd/goloader/obj"
    12  )
    13  
    14  func isOverflowInt32(offset int) bool {
    15  	if offset > 0x7FFFFFFF || offset < -0x80000000 {
    16  		return true
    17  	}
    18  	return false
    19  }
    20  
    21  func isOverflowInt24(offset int) bool {
    22  	if offset > 0x7FFFFF || offset < -0x800000 {
    23  		return true
    24  	}
    25  	return false
    26  }
    27  
    28  //go:linkname add runtime.add
    29  func add(p unsafe.Pointer, x uintptr) unsafe.Pointer
    30  
    31  //go:linkname adduintptr runtime.add
    32  func adduintptr(p uintptr, x int) unsafe.Pointer
    33  
    34  func putUint24(b []byte, v uint32) {
    35  	_ = b[2] // early bounds check to guarantee safety of writes below
    36  	b[0] = byte(v)
    37  	b[1] = byte(v >> 8)
    38  	b[2] = byte(v >> 16)
    39  }
    40  
    41  func alignof(i int, align int) int {
    42  	if i%align != 0 {
    43  		i = i + (align - i%align)
    44  	}
    45  	return i
    46  }
    47  
    48  func bytearrayAlign(b *[]byte, align int) {
    49  	length := len(*b)
    50  	if length%align != 0 {
    51  		*b = append(*b, make([]byte, align-length%align)...)
    52  	}
    53  }
    54  
    55  func bytearrayAlignNops(arch *sys.Arch, b *[]byte, align int) {
    56  	length := len(*b)
    57  	if length%align != 0 {
    58  		*b = append(*b, createArchNops(arch, align-length%align)...)
    59  	}
    60  }
    61  
    62  func createArchNops(arch *sys.Arch, size int) []byte {
    63  	switch arch.Name {
    64  	case sys.ArchARM.Name, sys.ArchARM64.Name:
    65  		return createArm64Nops(size)
    66  	case sys.Arch386.Name, sys.ArchAMD64.Name:
    67  		return createX86Amd64Nops(size)
    68  	default:
    69  		panic(fmt.Errorf("not support arch:%s", arch.Name))
    70  	}
    71  }
    72  
    73  func createX86Amd64Nops(size int) []byte {
    74  	nops := make([]byte, size)
    75  	for i := 0; i < size; i++ {
    76  		copy(nops[i:], x86amd64NOPcode)
    77  	}
    78  	return nops
    79  }
    80  
    81  func createArm64Nops(size int) []byte {
    82  	if size%sys.ArchARM.MinLC != 0 {
    83  		panic(fmt.Sprintf("can't make nop instruction if padding is not multiple of %d, got %d", sys.ArchARM.MinLC, size))
    84  	}
    85  	nops := make([]byte, size)
    86  	for i := 0; i < size; i += sys.ArchARM.MinLC {
    87  		copy(nops[i:], arm64Nopcode)
    88  	}
    89  	return nops
    90  }
    91  
    92  func putAddressAddOffset(byteOrder binary.ByteOrder, b []byte, offset *int, addr uint64) {
    93  	if PtrSize == Uint32Size {
    94  		byteOrder.PutUint32(b[*offset:], uint32(addr))
    95  	} else {
    96  		byteOrder.PutUint64(b[*offset:], uint64(addr))
    97  	}
    98  	*offset = *offset + PtrSize
    99  }
   100  
   101  func putAddress(byteOrder binary.ByteOrder, b []byte, addr uint64) {
   102  	if PtrSize == Uint32Size {
   103  		byteOrder.PutUint32(b, uint32(addr))
   104  	} else {
   105  		byteOrder.PutUint64(b, uint64(addr))
   106  	}
   107  }
   108  
   109  // sign extend a 24-bit integer
   110  func signext24(x int64) int32 {
   111  	return (int32(x) << 8) >> 8
   112  }
   113  
   114  func copy2Slice(dst []byte, src uintptr, size int) {
   115  	s := sliceHeader{
   116  		Data: src,
   117  		Len:  size,
   118  		Cap:  size,
   119  	}
   120  	copy(dst, *(*[]byte)(unsafe.Pointer(&s)))
   121  }
   122  
   123  func append2Slice(dst *[]byte, src uintptr, size int) {
   124  	s := sliceHeader{
   125  		Data: src,
   126  		Len:  size,
   127  		Cap:  size,
   128  	}
   129  	*dst = append(*dst, *(*[]byte)(unsafe.Pointer(&s))...)
   130  }
   131  
   132  // see runtime.internal.atomic.Loadp
   133  //
   134  //go:nosplit
   135  //go:noinline
   136  func loadp(ptr unsafe.Pointer) unsafe.Pointer {
   137  	return *(*unsafe.Pointer)(ptr)
   138  }
   139  
   140  //go:inline
   141  func grow(bytes *[]byte, size int) {
   142  	obj.Grow(bytes, size)
   143  }
   144  
   145  func getArch(archName string) *sys.Arch {
   146  	arch := &sys.Arch{}
   147  	for index := range sys.Archs {
   148  		if archName == sys.Archs[index].Name {
   149  			arch = sys.Archs[index]
   150  		}
   151  	}
   152  	return arch
   153  }
   154  
   155  func Mmap(size int) ([]byte, error) {
   156  	return mmap.Mmap(size)
   157  }
   158  
   159  func MmapData(size int) ([]byte, error) {
   160  	return mmap.MmapData(size)
   161  }
   162  
   163  func Munmap(b []byte) (err error) {
   164  	return mmap.Munmap(b)
   165  }
   166  
   167  func MakeThreadJITCodeExecutable(ptr uintptr, len int) {
   168  	mmap.MakeThreadJITCodeExecutable(ptr, len)
   169  }
   170  
   171  // see $GOROOT/src/cmd/internal/loader/loader.go:preprocess
   172  func ispreprocesssymbol(name string) bool {
   173  	if len(name) > 5 {
   174  		switch name[:5] {
   175  		case "$f32.", "$f64.", "$i64.":
   176  			return true
   177  		default:
   178  		}
   179  	}
   180  	return false
   181  }
   182  
   183  func preprocesssymbol(byteOrder binary.ByteOrder, name string, bytes []byte) error {
   184  	val, err := strconv.ParseUint(name[5:], 16, 64)
   185  	if err != nil {
   186  		return fmt.Errorf("failed to parse $-symbol %s: %v", name, err)
   187  	}
   188  	switch name[:5] {
   189  	case "$f32.":
   190  		if uint64(uint32(val)) != val {
   191  			return fmt.Errorf("$-symbol %s too large: %d", name, val)
   192  		}
   193  		byteOrder.PutUint32(bytes, uint32(val))
   194  		bytes = bytes[:4]
   195  	case "$f64.", "$i64.":
   196  		byteOrder.PutUint64(bytes, val)
   197  	default:
   198  		return fmt.Errorf("unrecognized $-symbol: %s", name)
   199  	}
   200  	return nil
   201  }
   202  
   203  func ptr2uint32slice(ptr uintptr, size int) *[]int32 {
   204  	s := sliceHeader{
   205  		Data: ptr,
   206  		Len:  size,
   207  		Cap:  size,
   208  	}
   209  	return (*[]int32)(unsafe.Pointer(&s))
   210  }