Skip to content

Instantly share code, notes, and snippets.

@Qix-
Last active February 15, 2019 05:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Qix-/f048052b53c67bb1596362731e178af3 to your computer and use it in GitHub Desktop.
Save Qix-/f048052b53c67bb1596362731e178af3 to your computer and use it in GitHub Desktop.
Example of how syscall support could be added to Terra without any dependencies
.PHONY: all
all: bin/test-syscall
bin/test-syscall: test-syscall.t syscall-macos-x64.t
@mkdir -p bin
terra $<
.PHONY: clean
clean:
rm -rf bin
-- Syscall wrapper for MacOS x64
local errno = global(uint64)
local syscall = macro(function (num, ...)
local args = {...}
-- make sure all args are <= size of uint64
for i=1,#args do
if terralib.sizeof(args[i].tree.type) > 8 then
error('syscall argument cannot be greater than 64 bits')
end
end
local arg1 = args[1]
local arg2 = args[2]
local arg3 = args[3]
local arg4 = args[4]
local arg5 = args[5]
local arg6 = args[6]
local instr = [[
syscall
jnc 1f
mov %rax, $0
mov $$-1, %rax
1:
]]
-- call appropriate stub
-- NOTE: there is evidence that RDX gets clobbered on MacOS.
-- we mark it as such here.
if #args == 0 then
return `terralib.asm(uint64, instr,
'=*m,={rax},{rax},~{rcx},~{r11},~{rdx}', true,
&errno,
[uint64](num + 0x2000000))
elseif #args == 1 then
return `terralib.asm(uint64, instr,
'=*m,={rax},{rax},{rdi},~{rcx},~{r11},~{rdx}', true,
&errno,
[uint64](num + 0x2000000),
[uint64](arg1))
elseif #args == 2 then
return `terralib.asm(uint64, instr,
'=*m,={rax},{rax},{rdi},{rsi},~{rcx},~{r11},~{rdx}', true,
&errno,
[uint64](num + 0x2000000),
[uint64](arg1), [uint64](arg2))
elseif #args == 3 then
return `terralib.asm(uint64, instr,
'=*m,={rax},{rax},{rdi},{rsi},{rdx},~{rcx},~{r11},~{rdx}', true,
&errno,
[uint64](num + 0x2000000),
[uint64](arg1), [uint64](arg2), [uint64](arg3))
elseif #args == 4 then
return `terralib.asm(uint64, instr,
'=*m,={rax},{rax},{rdi},{rsi},{rdx},{r10},~{rcx},~{r11},~{rdx}', true,
&errno,
[uint64](num + 0x2000000),
[uint64](arg1), [uint64](arg2), [uint64](arg3), [uint64](arg4))
elseif #args == 5 then
return `terralib.asm(uint64, instr,
'=*m,={rax},{rax},{rdi},{rsi},{rdx},{r10},{r8},~{rcx},~{r11},~{rdx}', true,
&errno,
[uint64](num + 0x2000000),
[uint64](arg1), [uint64](arg2), [uint64](arg3), [uint64](arg4), [uint64](arg5))
elseif #args == 6 then
return `terralib.asm(uint64, instr,
'=*m,={rax},{rax},{rdi},{rsi},{rdx},{r10},{r8},{r9},~{rcx},~{r11},~{rdx}', true,
&errno,
[uint64](num + 0x2000000),
[uint64](arg1), [uint64](arg2), [uint64](arg3), [uint64](arg4), [uint64](arg5), [uint64](arg6))
else
error('too many arguments to syscall')
end
end)
local DBG = terralib.includec('stdio.h')
-- https://opensource.apple.com/source/xnu/xnu-4903.221.2/bsd/kern/syscalls.master.auto.html
local terra _syscall_exit(exit_status: int) syscall(1, exit_status) end
local terra _syscall_write(fd: int, buf: &int8, size: uint64): uint64 return syscall(4, fd, buf, size) end
local terra _syscall_mmap_0(ptr: &opaque, size: uint64, protections: int, flags: int): uint64 return syscall(197, ptr, size, protections, flags) end
local terra _syscall_mmap_1(ptr: &opaque, size: uint64, protections: int, flags: int, fd: int, offset: uint64): &opaque return [&opaque](syscall(197, ptr, size, protections, flags, fd, offset)) end
local _syscall_mmap = terralib.overloadedfunction('_syscall_mmap', {_syscall_mmap_0, _syscall_mmap_1})
local terra _syscall_munmap(ptr: &opaque, size: uint64) syscall(73, ptr, size) end
-- TODO these belong somewhere else, not here.
local terra malloc4096(): &opaque
-- 0x03 = READ|WRITE (does not include EXEC) - XXX should it include EXEC?
-- 0x1002 = ANONYMOUS (no file, no offset) and PRIVATE
var ptrint: uint64 = _syscall_mmap_0(nil, 4096, 0x03, 0x1002);
if ptrint == [uint64](-1) then
DBG.printf("WARNING: mmap failed with errno: %lu\n", errno)
return nil
end
return [&opaque](ptrint)
end
local terra free4096(ptr: &opaque)
_syscall_munmap(ptr, 4096)
end
return {
exit = _syscall_exit,
write = _syscall_write,
mmap = _syscall_mmap,
munmap = _syscall_munmap,
-- TODO High level stuff that belongs elsewhere
malloc4096 = malloc4096,
free4096 = free4096
}
local sys = require('./syscall-macos-x64')
terra main()
var c: &int8 = [&int8](sys.malloc4096())
if c == nil then
sys.write(2, 'Allocation of page failed!\n', 27)
sys.exit(1)
end
sys.write(1, 'Created page!\n', 14)
var str: &int8 = "Hello from the page!\n"
var i: uint64 = 0
repeat
c[i] = str[i]
i = i + 1
until str[i] == 0
sys.write(1, c, i)
sys.write(1, 'Wrote page! Freeing it...\n', 26)
sys.free4096(c)
sys.write(1, 'Done!\n', 6)
sys.exit(0)
end
terralib.saveobj('bin/test-syscall', { main = main })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment