syscall_32bit.go raw

   1  // SPDX-License-Identifier: Apache-2.0
   2  // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
   3  
   4  //go:build (386 || arm) && (freebsd || linux || netbsd || windows)
   5  
   6  package purego
   7  
   8  // CDecl marks a function as being called using the __cdecl calling convention as defined in
   9  // the [MSDocs] when passed to NewCallback. It must be the first argument to the function.
  10  // This is only useful on 386 Windows, but it is safe to use on other platforms.
  11  //
  12  // [MSDocs]: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170
  13  type CDecl struct{}
  14  
  15  const (
  16  	maxArgs = 32
  17  )
  18  
  19  type syscall15Args struct {
  20  	fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15                uintptr
  21  	a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, a32 uintptr
  22  	f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16               uintptr
  23  	arm64_r8                                                                            uintptr
  24  }
  25  
  26  func (s *syscall15Args) Set(fn uintptr, ints []uintptr, floats []uintptr, r8 uintptr) {
  27  	s.fn = fn
  28  	s.a1 = ints[0]
  29  	s.a2 = ints[1]
  30  	s.a3 = ints[2]
  31  	s.a4 = ints[3]
  32  	s.a5 = ints[4]
  33  	s.a6 = ints[5]
  34  	s.a7 = ints[6]
  35  	s.a8 = ints[7]
  36  	s.a9 = ints[8]
  37  	s.a10 = ints[9]
  38  	s.a11 = ints[10]
  39  	s.a12 = ints[11]
  40  	s.a13 = ints[12]
  41  	s.a14 = ints[13]
  42  	s.a15 = ints[14]
  43  	s.a16 = ints[15]
  44  	s.a17 = ints[16]
  45  	s.a18 = ints[17]
  46  	s.a19 = ints[18]
  47  	s.a20 = ints[19]
  48  	s.a21 = ints[20]
  49  	s.a22 = ints[21]
  50  	s.a23 = ints[22]
  51  	s.a24 = ints[23]
  52  	s.a25 = ints[24]
  53  	s.a26 = ints[25]
  54  	s.a27 = ints[26]
  55  	s.a28 = ints[27]
  56  	s.a29 = ints[28]
  57  	s.a30 = ints[29]
  58  	s.a31 = ints[30]
  59  	s.a32 = ints[31]
  60  	s.f1 = floats[0]
  61  	s.f2 = floats[1]
  62  	s.f3 = floats[2]
  63  	s.f4 = floats[3]
  64  	s.f5 = floats[4]
  65  	s.f6 = floats[5]
  66  	s.f7 = floats[6]
  67  	s.f8 = floats[7]
  68  	s.f9 = floats[8]
  69  	s.f10 = floats[9]
  70  	s.f11 = floats[10]
  71  	s.f12 = floats[11]
  72  	s.f13 = floats[12]
  73  	s.f14 = floats[13]
  74  	s.f15 = floats[14]
  75  	s.f16 = floats[15]
  76  	s.arm64_r8 = r8
  77  }
  78  
  79  // SyscallN takes fn, a C function pointer and a list of arguments as uintptr.
  80  // There is an internal maximum number of arguments that SyscallN can take. It panics
  81  // when the maximum is exceeded. It returns the result and the libc error code if there is one.
  82  //
  83  // In order to call this function properly make sure to follow all the rules specified in [unsafe.Pointer]
  84  // especially point 4.
  85  //
  86  // NOTE: SyscallN does not properly call functions that have both integer and float parameters.
  87  // See discussion comment https://github.com/ebiten/purego/pull/1#issuecomment-1128057607
  88  // for an explanation of why that is.
  89  //
  90  // On amd64, if there are more than 8 floats the 9th and so on will be placed incorrectly on the
  91  // stack.
  92  //
  93  // The pragma go:nosplit is not needed at this function declaration because it uses go:uintptrescapes
  94  // which forces all the objects that the uintptrs point to onto the heap where a stack split won't affect
  95  // their memory location.
  96  //
  97  //go:uintptrescapes
  98  func SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) {
  99  	if fn == 0 {
 100  		panic("purego: fn is nil")
 101  	}
 102  	if len(args) > maxArgs {
 103  		panic("purego: too many arguments to SyscallN")
 104  	}
 105  	// add padding so there is no out-of-bounds slicing
 106  	var tmp [maxArgs]uintptr
 107  	copy(tmp[:], args)
 108  	return syscall_syscall15X(fn, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14])
 109  }
 110