@@ -5,6 +5,7 @@ package compiler
5
5
6
6
import (
7
7
"go/constant"
8
+ "strconv"
8
9
9
10
"golang.org/x/tools/go/ssa"
10
11
"tinygo.org/x/go-llvm"
@@ -14,6 +15,7 @@ import (
14
15
// OS/arch.
15
16
func (c * Compiler ) emitSyscall (frame * Frame , call * ssa.CallCommon ) (llvm.Value , error ) {
16
17
num , _ := constant .Uint64Val (call .Args [0 ].(* ssa.Const ).Value )
18
+ var syscallResult llvm.Value
17
19
switch {
18
20
case c .GOARCH == "amd64" && c .GOOS == "linux" :
19
21
// Sources:
@@ -43,25 +45,60 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
43
45
constraints += ",~{rcx},~{r11}"
44
46
fnType := llvm .FunctionType (c .uintptrType , argTypes , false )
45
47
target := llvm .InlineAsm (fnType , "syscall" , constraints , true , false , llvm .InlineAsmDialectIntel )
46
- syscallResult := c .builder .CreateCall (target , args , "" )
47
- // Return values: r1, r1, err uintptr
48
- // Pseudocode:
49
- // var err uintptr
50
- // if syscallResult < 0 && syscallResult > -4096 {
51
- // err = -syscallResult
52
- // }
53
- // return syscallResult, 0, err
54
- zero := llvm .ConstInt (c .uintptrType , 0 , false )
55
- inrange1 := c .builder .CreateICmp (llvm .IntSLT , syscallResult , llvm .ConstInt (c .uintptrType , 0 , false ), "" )
56
- inrange2 := c .builder .CreateICmp (llvm .IntSGT , syscallResult , llvm .ConstInt (c .uintptrType , 0xfffffffffffff000 , true ), "" ) // -4096
57
- hasError := c .builder .CreateAnd (inrange1 , inrange2 , "" )
58
- errResult := c .builder .CreateSelect (hasError , c .builder .CreateNot (syscallResult , "" ), zero , "syscallError" )
59
- retval := llvm .Undef (llvm .StructType ([]llvm.Type {c .uintptrType , c .uintptrType , c .uintptrType }, false ))
60
- retval = c .builder .CreateInsertValue (retval , syscallResult , 0 , "" )
61
- retval = c .builder .CreateInsertValue (retval , zero , 1 , "" )
62
- retval = c .builder .CreateInsertValue (retval , errResult , 2 , "" )
63
- return retval , nil
48
+ syscallResult = c .builder .CreateCall (target , args , "" )
49
+ case c .GOARCH == "arm" && c .GOOS == "linux" :
50
+ // Implement the EABI system call convention for Linux.
51
+ // Source: syscall(2) man page.
52
+ args := []llvm.Value {}
53
+ argTypes := []llvm.Type {}
54
+ // Constraints will look something like:
55
+ // ={r0},0,{r1},{r2},{r7},~{r3}
56
+ constraints := "={r0}"
57
+ for i , arg := range call .Args [1 :] {
58
+ constraints += "," + [... ]string {
59
+ "0" , // tie to output
60
+ "{r1}" ,
61
+ "{r2}" ,
62
+ "{r3}" ,
63
+ "{r4}" ,
64
+ "{r5}" ,
65
+ "{r6}" ,
66
+ }[i ]
67
+ llvmValue , err := c .parseExpr (frame , arg )
68
+ if err != nil {
69
+ return llvm.Value {}, err
70
+ }
71
+ args = append (args , llvmValue )
72
+ argTypes = append (argTypes , llvmValue .Type ())
73
+ }
74
+ args = append (args , llvm .ConstInt (c .uintptrType , num , false ))
75
+ argTypes = append (argTypes , c .uintptrType )
76
+ constraints += ",{r7}" // syscall number
77
+ for i := len (call .Args ) - 1 ; i < 4 ; i ++ {
78
+ // r0-r3 get clobbered after the syscall returns
79
+ constraints += ",~{r" + strconv .Itoa (i ) + "}"
80
+ }
81
+ fnType := llvm .FunctionType (c .uintptrType , argTypes , false )
82
+ target := llvm .InlineAsm (fnType , "svc #0" , constraints , true , false , 0 )
83
+ syscallResult = c .builder .CreateCall (target , args , "" )
64
84
default :
65
85
return llvm.Value {}, c .makeError (call .Pos (), "unknown GOOS/GOARCH for syscall: " + c .GOOS + "/" + c .GOARCH )
66
86
}
87
+ // Return values: r0, r1, err uintptr
88
+ // Pseudocode:
89
+ // var err uintptr
90
+ // if syscallResult < 0 && syscallResult > -4096 {
91
+ // err = -syscallResult
92
+ // }
93
+ // return syscallResult, 0, err
94
+ zero := llvm .ConstInt (c .uintptrType , 0 , false )
95
+ inrange1 := c .builder .CreateICmp (llvm .IntSLT , syscallResult , llvm .ConstInt (c .uintptrType , 0 , false ), "" )
96
+ inrange2 := c .builder .CreateICmp (llvm .IntSGT , syscallResult , llvm .ConstInt (c .uintptrType , 0xfffffffffffff000 , true ), "" ) // -4096
97
+ hasError := c .builder .CreateAnd (inrange1 , inrange2 , "" )
98
+ errResult := c .builder .CreateSelect (hasError , c .builder .CreateNot (syscallResult , "" ), zero , "syscallError" )
99
+ retval := llvm .Undef (llvm .StructType ([]llvm.Type {c .uintptrType , c .uintptrType , c .uintptrType }, false ))
100
+ retval = c .builder .CreateInsertValue (retval , syscallResult , 0 , "" )
101
+ retval = c .builder .CreateInsertValue (retval , zero , 1 , "" )
102
+ retval = c .builder .CreateInsertValue (retval , errResult , 2 , "" )
103
+ return retval , nil
67
104
}
0 commit comments