@@ -5,6 +5,7 @@ package compiler
55
66import (
77 "go/constant"
8+ "strconv"
89
910 "golang.org/x/tools/go/ssa"
1011 "tinygo.org/x/go-llvm"
@@ -14,6 +15,7 @@ import (
1415// OS/arch.
1516func (c * Compiler ) emitSyscall (frame * Frame , call * ssa.CallCommon ) (llvm.Value , error ) {
1617 num , _ := constant .Uint64Val (call .Args [0 ].(* ssa.Const ).Value )
18+ var syscallResult llvm.Value
1719 switch {
1820 case c .GOARCH == "amd64" && c .GOOS == "linux" :
1921 // Sources:
@@ -43,25 +45,60 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
4345 constraints += ",~{rcx},~{r11}"
4446 fnType := llvm .FunctionType (c .uintptrType , argTypes , false )
4547 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 , "" )
6484 default :
6585 return llvm.Value {}, c .makeError (call .Pos (), "unknown GOOS/GOARCH for syscall: " + c .GOOS + "/" + c .GOARCH )
6686 }
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
67104}
0 commit comments