stdlib.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. ; vim:ft=fasm:
  2. include 'syscall.inc'
  3. include 'utils.inc'
  4. ;include 'struct.inc'
  5. ;include 'align.inc'
  6. include '@@.inc'
  7. if ~ defined stdlib
  8. restore stdlib
  9. define stdlib
  10. STDIN_FILENO equ 0
  11. STDOUT_FILENO equ 1
  12. STDERR_FILENO equ 2
  13. ; max i32
  14. PID_MAX equ (0x#7f#ff#ff#ff)
  15. ;;; SYSCALLS: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  16. macro fork
  17. do_syscall syscall.SYS_fork
  18. end macro
  19. macro wait4 pid*, status_ptr*, options*, rusage*
  20. do_syscall syscall.SYS_wait4, pid, status_ptr, options, rusage
  21. end macro
  22. macro write fd*, buf*, size*
  23. do_syscall syscall.SYS_write, fd, buf, size
  24. end macro
  25. macro writeZ fd*, strZ
  26. local tmp_str
  27. tmp_str = rsi
  28. mov tmp_str, strZ
  29. using_regs rdi
  30. strlenz tmp_str
  31. end using_regs
  32. write fd, tmp_str, rax
  33. end macro
  34. macro execve pathname*, argv*, envp*
  35. do_syscall syscall.SYS_execve, pathname, argv, envp
  36. end macro
  37. macro exit status*
  38. do_syscall syscall.SYS_exit, status
  39. xor rsp, rsp
  40. ret
  41. end macro
  42. macro dup2 oldfd*, newfd*
  43. do_syscall syscall.SYS_dup2, oldfd, newfd
  44. end macro
  45. macro pipe pipefd2*
  46. do_syscall syscall.SYS_pipe, pipefd2
  47. end macro
  48. macro open pathZ*, flags*, mode
  49. do_syscall syscall.SYS_open, pathZ, flags, mode
  50. end macro
  51. namespace open
  52. define RDONLY 00o
  53. define WRONLY 01o
  54. define RDWR 02o
  55. define CREAT ( 0100o)
  56. define EXCL ( 0200o)
  57. define NOCTTY ( 0400o)
  58. define TRUNC ( 01000o)
  59. define APPEND ( 02000o)
  60. define NONBLOCK ( 04000o)
  61. define DSYNC ( 010000o)
  62. define SYNC ( 04010000o)
  63. define RSYNC ( 04010000o)
  64. define DIRECTORY ( 0200000o)
  65. define NOFOLLOW ( 0400000o)
  66. define CLOEXEC ( 02000000o)
  67. define ASYNC ( 020000o)
  68. define DIRECT ( 040000o)
  69. define LARGEFILE ( 0100000o)
  70. define NOATIME ( 01000000o)
  71. define PATH (010000000o)
  72. define TMPFILE (020200000o)
  73. define NDELAY (O_NONBLOCK)
  74. end namespace
  75. macro close fd*
  76. do_syscall syscall.SYS_close, fd
  77. end macro
  78. macro pidfd_open pid*, flags*
  79. do_syscall syscall.SYS_pidfd_open, pid, flags
  80. end macro
  81. struct pollfd
  82. fd dd ?
  83. events dw ?
  84. revents dw ?
  85. ends
  86. namespace pool
  87. define IN 0x001
  88. define PRI 0x002
  89. define OUT 0x004
  90. define ERR 0x008
  91. define HUP 0x010
  92. define NVAL 0x020
  93. define RDNORM 0x040
  94. define RDBAND 0x080
  95. end namespace
  96. macro poll fds*, nfds*, timeout*
  97. do_syscall syscall.SYS_poll, fds, nfds, timeout
  98. end macro
  99. ;;; SYSCALLS: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  100. ;;; PREP_ARGS: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  101. ;struct args
  102. ; .count dq ?
  103. ; .ptr dq ?
  104. ;end struct
  105. macro prep_args_to_struct args_ptr*
  106. .argc = rsp
  107. .argv_ptr = .argc + qword
  108. mov2mem qword [args_ptr + args.count], qword [.argc]
  109. mov2mem qword [args_ptr + args.ptr], .argv_ptr
  110. end macro
  111. macro prep_args argc:rdi, argv:rsi, env:rdx
  112. mov argc, [rsp]
  113. lea argv, qword [rsp + qword]
  114. lea env, qword [argv + (argc + 1) * qword]
  115. end macro
  116. ;;; PREP_ARGS: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  117. ;;; MEMCPY: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  118. macro memcpy dst*, src*, size*
  119. call_args memcpy_impl, dst, src, size
  120. end macro
  121. proc memcpy_impl
  122. .dst = rdi
  123. .src = rsi
  124. .size = rdx
  125. .counter = rcx
  126. .tmp_byte = al
  127. test .size, .size
  128. je .done
  129. xor .counter, .counter
  130. .loop:
  131. mov2mem byte [.dst + .counter], byte [.src + .counter], .tmp_byte
  132. cmp .counter, .size
  133. lea .counter, [.counter + 1]
  134. jne .loop
  135. .done:
  136. end proc
  137. ;;; MEMCPY: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  138. ;;; MEMSET: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  139. macro memset buf*, byt*, size*
  140. call_args memset_impl, buf, byt, size
  141. end macro
  142. proc memset_impl
  143. .dst = rdi
  144. .byte = sil
  145. .size = rdx
  146. .loop:
  147. cmp .size, 0
  148. jle .done
  149. lea .size, [.size - 1]
  150. mov byte [.dst + .size], .byte
  151. jmp .loop
  152. .done:
  153. end proc
  154. ;;; MEMSET: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  155. ;;; STRLENZ: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  156. macro strlenz strZ*
  157. call_args strlenz_impl, strZ
  158. end macro
  159. proc strlenz_impl
  160. .str = rdi
  161. .counter = rax
  162. mov .counter, -1
  163. .loop:
  164. cmp byte [.str + .counter + 1], 0
  165. lea .counter, [.counter + 1]
  166. jnz .loop
  167. end proc
  168. ;;; STRLENZ: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  169. ;;; PRINT: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  170. ; `out_buf` should point at the end of buffer that can hold at least 20 bytes
  171. ; return: begining of the number in `out_buf`, size in `rcx`
  172. macro print fmt*, num*, out_buf*
  173. ;; EXAMPLE:
  174. ;; mov rax, print_buf
  175. ;; print u, -1, rax
  176. ;; write STDOUT_FILENO, rax, rcx
  177. local size
  178. size = rcx
  179. mov size, out_buf
  180. mov_args num, out_buf
  181. ; TODO: add x to print hex number
  182. match =u?, fmt
  183. call print_uint_impl
  184. else match =i?, fmt
  185. call print_sint_impl
  186. else
  187. err 'unsupported format: ', `fmt
  188. end match
  189. sub size, rax
  190. end macro
  191. proc print_sint_impl
  192. .is_neg = r8
  193. using_regs .is_neg
  194. .num = rdi
  195. xor .is_neg, .is_neg
  196. cmp .num, 0
  197. jge .uint
  198. .negative:
  199. mov .is_neg, 1
  200. neg .num
  201. .uint:
  202. call print_uint_impl
  203. test .is_neg, .is_neg
  204. jz .done
  205. lea rax, [rax - 1]
  206. mov byte [rax], '-'
  207. .done:
  208. end using_regs
  209. end proc
  210. proc print_uint_impl
  211. mov rax, rdi
  212. .uint = rax
  213. .base = rdi
  214. mov .base, 10
  215. .out_buf = rsi
  216. .loop:
  217. xor rdx, rdx
  218. div .base
  219. add dl, '0'
  220. lea .out_buf, [.out_buf - 1]
  221. mov [.out_buf], dl
  222. test .uint, .uint
  223. jnz .loop
  224. mov rax, .out_buf
  225. end proc
  226. ;;; PRINT: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  227. ;;; ACCESS: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  228. access.F_OK equ 0
  229. access.R_OK equ 4
  230. access.W_OK equ 2
  231. access.X_OK equ 1
  232. macro access path*, mode*
  233. do_syscall syscall.SYS_access, path, mode
  234. end macro
  235. ;;; ACCESS: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  236. ;;; STAT: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  237. struct timespec
  238. sec dq ?
  239. nsec dq ?
  240. ends
  241. struct stat_struct
  242. st_dev dq ?
  243. st_ino dq ?
  244. st_nlink dq ?
  245. st_mode dd ?
  246. ;;; mode
  247. macro .S_ISREG buf*
  248. mov eax, [buf + stat_struct.st_mode]
  249. and eax, stat_struct.S_IFMT
  250. test eax, stat_struct.S_IFREG
  251. end macro
  252. .S_IFMT equ 170000o
  253. .S_IFDIR equ 040000o
  254. .S_IFCHR equ 020000o
  255. .S_IFBLK equ 060000o
  256. .S_IFREG equ 100000o
  257. .S_IFIFO equ 010000o
  258. .S_IFLNK equ 120000o
  259. .S_IFSOCK equ 140000o
  260. ;;; mode
  261. st_uid dd ?
  262. st_gid dd ?
  263. __pad0 dd ?
  264. st_rdev dq ?
  265. st_size dq ?
  266. st_blksize dq ?
  267. st_blocks dq ?
  268. iterate X, a, m, c
  269. st_#X#tim timespec
  270. end iterate
  271. repeat 3
  272. __unused#% dq 0
  273. end repeat
  274. ends
  275. macro stat pathZ*, stat_buf*
  276. do_syscall syscall.SYS_stat, pathZ, stat_buf
  277. end macro
  278. ;;; STAT: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  279. ;;; WAIT: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  280. macro waitpid pid*, status_ptr*, options*
  281. wait4 pid, status_ptr, options, 0
  282. end macro
  283. macro wait status_ptr*
  284. waitpid -1, status_ptr, 0
  285. end macro
  286. namespace wstatus
  287. macro TERMSIG status*
  288. mov eax, status
  289. and eax, 0x7f
  290. end macro
  291. macro IFEXITED status*
  292. wstatus.TERMSIG status
  293. test eax, eax
  294. end macro
  295. macro EXITSTATUS status*
  296. mov eax, status
  297. and eax, 0xff00
  298. sar eax, 8
  299. end macro
  300. end namespace
  301. ;;; WAIT: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  302. ;;; BASENAME: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  303. ; return: path in rax, path_len in rcx
  304. macro basename_posix path*, path_len*
  305. call_args basename_posix_impl, path, path_len
  306. end macro
  307. macro basename_posixZ pathZ*
  308. strlenz pathZ
  309. mov rsi, rax
  310. call basename_posix_impl
  311. end macro
  312. proc basename_posix_impl
  313. .str = rdi
  314. .size = rsi
  315. .end_index = r11
  316. .start_index = rdx
  317. .path_sep = '/'
  318. using_regs .end_index
  319. test .size, .size
  320. jz .zero_input
  321. lea .end_index, [.size - 1]
  322. @@:
  323. cmp byte [.str + .end_index], .path_sep
  324. jne @f
  325. test .end_index, .end_index
  326. jz .zero_input
  327. lea .end_index, [.end_index - 1]
  328. jmp @b
  329. @@:
  330. mov .start_index, .end_index
  331. lea .end_index, [.end_index + 1]
  332. @@:
  333. cmp byte [.str + .start_index], .path_sep
  334. je @f
  335. test .start_index, .start_index
  336. jz .zero_start
  337. lea .start_index, [.start_index - 1]
  338. jmp @b
  339. @@:
  340. lea rcx, [.start_index + 1]
  341. lea rax, [.str + rcx]
  342. sub .end_index, rcx
  343. mov rcx, .end_index
  344. jmp .end_snapshot
  345. .zero_start:
  346. mov rax, .str
  347. mov rcx, .end_index
  348. jmp .end_snapshot
  349. .zero_input:
  350. mov rax, 0
  351. mov rcx, 0
  352. .end_snapshot:
  353. end using_regs
  354. end proc
  355. ;;; BASENAME: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  356. ;;; STEM: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  357. ; return: path in rax, path_len in rcx
  358. macro stem_posix path*, path_len*
  359. call_args stem_posix_impl, path, path_len
  360. end macro
  361. macro stem_posixZ pathZ*
  362. strlenz pathZ
  363. mov rsi, rax
  364. call stem_posix_impl
  365. end macro
  366. proc stem_posix_impl
  367. .path = r10
  368. .len = r9
  369. .dot = '.'
  370. using_regs .path, .len
  371. mov .path, rdi
  372. mov .len, rsi
  373. .i = rsi
  374. .char = dil
  375. call basename_posix_impl
  376. mov .i, rcx
  377. @@:
  378. test .i, .i
  379. jz @f
  380. lea .i, [.i - 1]
  381. mov .char, [rax + .i]
  382. cmp .char, .dot
  383. je .dot_found
  384. jmp @b
  385. @@:
  386. .dot_not_found:
  387. jmp .end_snapshot
  388. .dot_found:
  389. test .i, .i
  390. jz .index_zero
  391. mov rcx, .i
  392. jmp .end_snapshot
  393. .index_zero:
  394. mov rax, .path
  395. mov rcx, .len
  396. .end_snapshot:
  397. end using_regs
  398. end proc
  399. ;;; STEM: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  400. ;;; ALIGN_TO: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  401. macro align_to n*, to*
  402. call_args align_to_impl, n, to
  403. end macro
  404. proc align_to_impl
  405. .n = rdi
  406. .to = rsi
  407. lea rax, [.to - 1]
  408. mov rcx, rax
  409. and rcx, .n
  410. sub .to, rcx
  411. and rax, .to
  412. add rax, .n
  413. end proc
  414. ;;; ALIGN_TO: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  415. ;;; STON: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  416. ; string to number
  417. ; to check failure use:
  418. ; jz .error_happend
  419. macro stonZ fmt*, string*
  420. strlenz string
  421. ston fmt, string, rax
  422. end macro
  423. macro ston fmt*, string*, len*
  424. ; unsigned decimal
  425. match =u10, fmt
  426. call_args ston_#fmt#_impl, string, len
  427. else ; TODO: add formats for signed decimal, hex, binary and octal
  428. err 'invalid fmt: ', `fmt
  429. end match
  430. end macro
  431. proc ston_u10_impl
  432. .str = rdi
  433. .len = rsi
  434. .tmp_num = rdx
  435. .counter = rcx
  436. xor rax, rax
  437. xor .counter, .counter
  438. .loop:
  439. cmp byte [.str + .counter], '0'
  440. jl .error
  441. cmp byte [.str + .counter], '9'
  442. jg .error
  443. mov .tmp_num, rax
  444. mov rax, 10
  445. mul .tmp_num
  446. movzx .tmp_num, byte [.str + .counter]
  447. lea rax, [rax + .tmp_num - '0']
  448. lea .counter, [.counter + 1]
  449. cmp .counter, .len
  450. jl .loop
  451. .done:
  452. using_regs rax
  453. lahf
  454. and ah, 10111111b
  455. sahf
  456. end using_regs
  457. ret
  458. .error:
  459. lahf
  460. or ah, 01000000b
  461. sahf
  462. end proc
  463. ;;; STON: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  464. ;;; SIGNAL: START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  465. enum SIG
  466. S_HUP = 1
  467. S_INT = 2
  468. S_QUIT = 3
  469. S_ILL = 4
  470. S_TRAP = 5
  471. S_ABRT = 6
  472. S_IOT = S_ABRT
  473. S_BUS = 7
  474. S_FPE = 8
  475. S_KILL = 9
  476. S_USR1 = 10
  477. S_SEGV = 11
  478. S_USR2 = 12
  479. S_PIPE = 13
  480. S_ALRM = 14
  481. S_TERM = 15
  482. S_STKFLT = 16
  483. S_CHLD = 17
  484. S_CONT = 18
  485. S_STOP = 19
  486. S_TSTP = 20
  487. S_TTIN = 21
  488. S_TTOU = 22
  489. S_URG = 23
  490. S_XCPU = 24
  491. S_XFSZ = 25
  492. S_VTALRM = 26
  493. S_PROF = 27
  494. S_WINCH = 28
  495. S_IO = 29
  496. S_POLL = 29
  497. S_PWR = 30
  498. S_SYS = 31
  499. S_UNUSED = S_SYS
  500. _NSIG = 65
  501. H_ERR = -1
  502. H_DFL = 0
  503. H_IGN = 1
  504. end enum
  505. enum SA
  506. NOCLDSTOP = 1
  507. NOCLDWAIT = 2
  508. SIGINFO = 4
  509. ONSTACK = 0x08000000
  510. RESTART = 0x10000000
  511. NODEFER = 0x40000000
  512. RESETHAND = 0x80000000
  513. RESTORER = 0x04000000
  514. end enum
  515. struct k_sigaction
  516. handler dq ?
  517. flags dq ?
  518. restorer dq ?
  519. mask rd 2
  520. ends
  521. macro sigaction sig*, action*, old_action*, sigset_size*
  522. do_syscall syscall.SYS_rt_sigaction, sig, action, old_action, sigset_size
  523. end macro
  524. macro signal signum*, handler*
  525. call_args signal_impl, signum, handler
  526. end macro
  527. proc _signal_restorer
  528. do_syscall syscall.SYS_rt_sigreturn
  529. end proc
  530. ; WARNING: DOES NOT return old sigaction handler (which libc `signal` does)
  531. proc signal_impl
  532. stack_frame sizeof.k_sigaction
  533. .sigaction = stack_frame.use(sizeof.k_sigaction)
  534. mov [.sigaction + k_sigaction.handler], rsi
  535. mov [.sigaction + k_sigaction.flags], (SA.RESTORER or SA.RESTART)
  536. mov [.sigaction + k_sigaction.restorer], _signal_restorer
  537. lea rsi, [.sigaction]
  538. xor rdx, rdx
  539. sigaction rdi, rsi, rdx, (dword * 2)
  540. end stack_frame
  541. end proc
  542. ;;; SIGNAL: END ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  543. end if