123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658 |
- ; vim:ft=fasm:
- include 'syscall.inc'
- include 'utils.inc'
- ;include 'struct.inc'
- ;include 'align.inc'
- include '@@.inc'
- if ~ defined stdlib
- restore stdlib
- define stdlib
- STDIN_FILENO equ 0
- STDOUT_FILENO equ 1
- STDERR_FILENO equ 2
- ; max i32
- PID_MAX equ (0x#7f#ff#ff#ff)
- ;;; SYSCALLS: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- macro fork
- do_syscall syscall.SYS_fork
- end macro
- macro wait4 pid*, status_ptr*, options*, rusage*
- do_syscall syscall.SYS_wait4, pid, status_ptr, options, rusage
- end macro
- macro write fd*, buf*, size*
- do_syscall syscall.SYS_write, fd, buf, size
- end macro
- macro writeZ fd*, strZ
- local tmp_str
- tmp_str = rsi
- mov tmp_str, strZ
- using_regs rdi
- strlenz tmp_str
- end using_regs
- write fd, tmp_str, rax
- end macro
- macro execve pathname*, argv*, envp*
- do_syscall syscall.SYS_execve, pathname, argv, envp
- end macro
- macro exit status*
- do_syscall syscall.SYS_exit, status
- xor rsp, rsp
- ret
- end macro
- macro dup2 oldfd*, newfd*
- do_syscall syscall.SYS_dup2, oldfd, newfd
- end macro
- macro pipe pipefd2*
- do_syscall syscall.SYS_pipe, pipefd2
- end macro
- macro open pathZ*, flags*, mode
- do_syscall syscall.SYS_open, pathZ, flags, mode
- end macro
- namespace open
- define RDONLY 00o
- define WRONLY 01o
- define RDWR 02o
- define CREAT ( 0100o)
- define EXCL ( 0200o)
- define NOCTTY ( 0400o)
- define TRUNC ( 01000o)
- define APPEND ( 02000o)
- define NONBLOCK ( 04000o)
- define DSYNC ( 010000o)
- define SYNC ( 04010000o)
- define RSYNC ( 04010000o)
- define DIRECTORY ( 0200000o)
- define NOFOLLOW ( 0400000o)
- define CLOEXEC ( 02000000o)
- define ASYNC ( 020000o)
- define DIRECT ( 040000o)
- define LARGEFILE ( 0100000o)
- define NOATIME ( 01000000o)
- define PATH (010000000o)
- define TMPFILE (020200000o)
- define NDELAY (O_NONBLOCK)
- end namespace
- macro close fd*
- do_syscall syscall.SYS_close, fd
- end macro
- macro pidfd_open pid*, flags*
- do_syscall syscall.SYS_pidfd_open, pid, flags
- end macro
- struct pollfd
- fd dd ?
- events dw ?
- revents dw ?
- ends
- namespace pool
- define IN 0x001
- define PRI 0x002
- define OUT 0x004
- define ERR 0x008
- define HUP 0x010
- define NVAL 0x020
- define RDNORM 0x040
- define RDBAND 0x080
- end namespace
- macro poll fds*, nfds*, timeout*
- do_syscall syscall.SYS_poll, fds, nfds, timeout
- end macro
- ;;; SYSCALLS: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; PREP_ARGS: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;struct args
- ; .count dq ?
- ; .ptr dq ?
- ;end struct
- macro prep_args_to_struct args_ptr*
- .argc = rsp
- .argv_ptr = .argc + qword
- mov2mem qword [args_ptr + args.count], qword [.argc]
- mov2mem qword [args_ptr + args.ptr], .argv_ptr
- end macro
- macro prep_args argc:rdi, argv:rsi, env:rdx
- mov argc, [rsp]
- lea argv, qword [rsp + qword]
- lea env, qword [argv + (argc + 1) * qword]
- end macro
- ;;; PREP_ARGS: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; MEMCPY: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- macro memcpy dst*, src*, size*
- call_args memcpy_impl, dst, src, size
- end macro
- proc memcpy_impl
- .dst = rdi
- .src = rsi
- .size = rdx
- .counter = rcx
- .tmp_byte = al
- test .size, .size
- je .done
- xor .counter, .counter
- .loop:
- mov2mem byte [.dst + .counter], byte [.src + .counter], .tmp_byte
- cmp .counter, .size
- lea .counter, [.counter + 1]
- jne .loop
- .done:
- end proc
- ;;; MEMCPY: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; MEMSET: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- macro memset buf*, byt*, size*
- call_args memset_impl, buf, byt, size
- end macro
- proc memset_impl
- .dst = rdi
- .byte = sil
- .size = rdx
- .loop:
- cmp .size, 0
- jle .done
- lea .size, [.size - 1]
- mov byte [.dst + .size], .byte
- jmp .loop
-
- .done:
- end proc
- ;;; MEMSET: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; STRLENZ: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- macro strlenz strZ*
- call_args strlenz_impl, strZ
- end macro
- proc strlenz_impl
- .str = rdi
- .counter = rax
- mov .counter, -1
- .loop:
- cmp byte [.str + .counter + 1], 0
- lea .counter, [.counter + 1]
- jnz .loop
- end proc
- ;;; STRLENZ: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; PRINT: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; `out_buf` should point at the end of buffer that can hold at least 20 bytes
- ; return: begining of the number in `out_buf`, size in `rcx`
- macro print fmt*, num*, out_buf*
- ;; EXAMPLE:
- ;; mov rax, print_buf
- ;; print u, -1, rax
- ;; write STDOUT_FILENO, rax, rcx
- local size
- size = rcx
- mov size, out_buf
- mov_args num, out_buf
- ; TODO: add x to print hex number
- match =u?, fmt
- call print_uint_impl
- else match =i?, fmt
- call print_sint_impl
- else
- err 'unsupported format: ', `fmt
- end match
- sub size, rax
- end macro
- proc print_sint_impl
- .is_neg = r8
- using_regs .is_neg
- .num = rdi
- xor .is_neg, .is_neg
- cmp .num, 0
- jge .uint
- .negative:
- mov .is_neg, 1
- neg .num
- .uint:
- call print_uint_impl
- test .is_neg, .is_neg
- jz .done
- lea rax, [rax - 1]
- mov byte [rax], '-'
- .done:
- end using_regs
- end proc
- proc print_uint_impl
- mov rax, rdi
- .uint = rax
- .base = rdi
- mov .base, 10
- .out_buf = rsi
- .loop:
- xor rdx, rdx
- div .base
- add dl, '0'
- lea .out_buf, [.out_buf - 1]
- mov [.out_buf], dl
- test .uint, .uint
- jnz .loop
- mov rax, .out_buf
- end proc
- ;;; PRINT: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; ACCESS: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- access.F_OK equ 0
- access.R_OK equ 4
- access.W_OK equ 2
- access.X_OK equ 1
- macro access path*, mode*
- do_syscall syscall.SYS_access, path, mode
- end macro
- ;;; ACCESS: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; STAT: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- struct timespec
- sec dq ?
- nsec dq ?
- ends
- struct stat_struct
- st_dev dq ?
- st_ino dq ?
- st_nlink dq ?
- st_mode dd ?
- ;;; mode
- macro .S_ISREG buf*
- mov eax, [buf + stat_struct.st_mode]
- and eax, stat_struct.S_IFMT
- test eax, stat_struct.S_IFREG
- end macro
- .S_IFMT equ 170000o
- .S_IFDIR equ 040000o
- .S_IFCHR equ 020000o
- .S_IFBLK equ 060000o
- .S_IFREG equ 100000o
- .S_IFIFO equ 010000o
- .S_IFLNK equ 120000o
- .S_IFSOCK equ 140000o
- ;;; mode
- st_uid dd ?
- st_gid dd ?
- __pad0 dd ?
- st_rdev dq ?
- st_size dq ?
- st_blksize dq ?
- st_blocks dq ?
- iterate X, a, m, c
- st_#X#tim timespec
- end iterate
- repeat 3
- __unused#% dq 0
- end repeat
- ends
- macro stat pathZ*, stat_buf*
- do_syscall syscall.SYS_stat, pathZ, stat_buf
- end macro
- ;;; STAT: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; WAIT: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- macro waitpid pid*, status_ptr*, options*
- wait4 pid, status_ptr, options, 0
- end macro
- macro wait status_ptr*
- waitpid -1, status_ptr, 0
- end macro
- namespace wstatus
- macro TERMSIG status*
- mov eax, status
- and eax, 0x7f
- end macro
- macro IFEXITED status*
- wstatus.TERMSIG status
- test eax, eax
- end macro
- macro EXITSTATUS status*
- mov eax, status
- and eax, 0xff00
- sar eax, 8
- end macro
- end namespace
- ;;; WAIT: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; BASENAME: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; return: path in rax, path_len in rcx
- macro basename_posix path*, path_len*
- call_args basename_posix_impl, path, path_len
- end macro
- macro basename_posixZ pathZ*
- strlenz pathZ
- mov rsi, rax
- call basename_posix_impl
- end macro
- proc basename_posix_impl
- .str = rdi
- .size = rsi
- .end_index = r11
- .start_index = rdx
- .path_sep = '/'
- using_regs .end_index
- test .size, .size
- jz .zero_input
- lea .end_index, [.size - 1]
- @@:
- cmp byte [.str + .end_index], .path_sep
- jne @f
- test .end_index, .end_index
- jz .zero_input
- lea .end_index, [.end_index - 1]
- jmp @b
- @@:
- mov .start_index, .end_index
- lea .end_index, [.end_index + 1]
- @@:
- cmp byte [.str + .start_index], .path_sep
- je @f
- test .start_index, .start_index
- jz .zero_start
- lea .start_index, [.start_index - 1]
- jmp @b
- @@:
- lea rcx, [.start_index + 1]
- lea rax, [.str + rcx]
- sub .end_index, rcx
- mov rcx, .end_index
- jmp .end_snapshot
- .zero_start:
- mov rax, .str
- mov rcx, .end_index
- jmp .end_snapshot
- .zero_input:
- mov rax, 0
- mov rcx, 0
- .end_snapshot:
- end using_regs
- end proc
- ;;; BASENAME: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; STEM: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; return: path in rax, path_len in rcx
- macro stem_posix path*, path_len*
- call_args stem_posix_impl, path, path_len
- end macro
- macro stem_posixZ pathZ*
- strlenz pathZ
- mov rsi, rax
- call stem_posix_impl
- end macro
- proc stem_posix_impl
- .path = r10
- .len = r9
- .dot = '.'
- using_regs .path, .len
- mov .path, rdi
- mov .len, rsi
- .i = rsi
- .char = dil
- call basename_posix_impl
- mov .i, rcx
- @@:
- test .i, .i
- jz @f
- lea .i, [.i - 1]
- mov .char, [rax + .i]
- cmp .char, .dot
- je .dot_found
- jmp @b
- @@:
- .dot_not_found:
- jmp .end_snapshot
- .dot_found:
- test .i, .i
- jz .index_zero
- mov rcx, .i
- jmp .end_snapshot
- .index_zero:
- mov rax, .path
- mov rcx, .len
- .end_snapshot:
- end using_regs
- end proc
- ;;; STEM: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; ALIGN_TO: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- macro align_to n*, to*
- call_args align_to_impl, n, to
- end macro
- proc align_to_impl
- .n = rdi
- .to = rsi
- lea rax, [.to - 1]
- mov rcx, rax
- and rcx, .n
- sub .to, rcx
- and rax, .to
- add rax, .n
- end proc
- ;;; ALIGN_TO: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; STON: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ; string to number
- ; to check failure use:
- ; jz .error_happend
- macro stonZ fmt*, string*
- strlenz string
- ston fmt, string, rax
- end macro
- macro ston fmt*, string*, len*
- ; unsigned decimal
- match =u10, fmt
- call_args ston_#fmt#_impl, string, len
- else ; TODO: add formats for signed decimal, hex, binary and octal
- err 'invalid fmt: ', `fmt
- end match
- end macro
- proc ston_u10_impl
- .str = rdi
- .len = rsi
- .tmp_num = rdx
- .counter = rcx
- xor rax, rax
- xor .counter, .counter
- .loop:
- cmp byte [.str + .counter], '0'
- jl .error
- cmp byte [.str + .counter], '9'
- jg .error
- mov .tmp_num, rax
- mov rax, 10
- mul .tmp_num
- movzx .tmp_num, byte [.str + .counter]
- lea rax, [rax + .tmp_num - '0']
- lea .counter, [.counter + 1]
- cmp .counter, .len
- jl .loop
- .done:
- using_regs rax
- lahf
- and ah, 10111111b
- sahf
- end using_regs
- ret
- .error:
- lahf
- or ah, 01000000b
- sahf
- end proc
- ;;; STON: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; SIGNAL: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- enum SIG
- S_HUP = 1
- S_INT = 2
- S_QUIT = 3
- S_ILL = 4
- S_TRAP = 5
- S_ABRT = 6
- S_IOT = S_ABRT
- S_BUS = 7
- S_FPE = 8
- S_KILL = 9
- S_USR1 = 10
- S_SEGV = 11
- S_USR2 = 12
- S_PIPE = 13
- S_ALRM = 14
- S_TERM = 15
- S_STKFLT = 16
- S_CHLD = 17
- S_CONT = 18
- S_STOP = 19
- S_TSTP = 20
- S_TTIN = 21
- S_TTOU = 22
- S_URG = 23
- S_XCPU = 24
- S_XFSZ = 25
- S_VTALRM = 26
- S_PROF = 27
- S_WINCH = 28
- S_IO = 29
- S_POLL = 29
- S_PWR = 30
- S_SYS = 31
- S_UNUSED = S_SYS
- _NSIG = 65
- H_ERR = -1
- H_DFL = 0
- H_IGN = 1
- end enum
- enum SA
- NOCLDSTOP = 1
- NOCLDWAIT = 2
- SIGINFO = 4
- ONSTACK = 0x08000000
- RESTART = 0x10000000
- NODEFER = 0x40000000
- RESETHAND = 0x80000000
- RESTORER = 0x04000000
- end enum
- struct k_sigaction
- handler dq ?
- flags dq ?
- restorer dq ?
- mask rd 2
- ends
- macro sigaction sig*, action*, old_action*, sigset_size*
- do_syscall syscall.SYS_rt_sigaction, sig, action, old_action, sigset_size
- end macro
- macro signal signum*, handler*
- call_args signal_impl, signum, handler
- end macro
- proc _signal_restorer
- do_syscall syscall.SYS_rt_sigreturn
- end proc
- ; WARNING: DOES NOT return old sigaction handler (which libc `signal` does)
- proc signal_impl
- stack_frame sizeof.k_sigaction
- .sigaction = stack_frame.use(sizeof.k_sigaction)
- mov [.sigaction + k_sigaction.handler], rsi
- mov [.sigaction + k_sigaction.flags], (SA.RESTORER or SA.RESTART)
- mov [.sigaction + k_sigaction.restorer], _signal_restorer
- lea rsi, [.sigaction]
- xor rdx, rdx
- sigaction rdi, rsi, rdx, (dword * 2)
- end stack_frame
- end proc
- ;;; SIGNAL: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- end if
|