@@ -*- asm -*- @@ Call Linux select(2) from ARM assembly. @@ @@ https://syscalls.w3challs.com/?arch=arm_thumb says @@ _newselect is system call 142 (0x8e in r7) with int n in @@ r0, fd_set *inp in r1, fd_set *outp in r2, fd_set *exp in @@ r3, and struct timeval *tvp in r4. The struct timeval @@ apparently consists of two 32-bit words, one for tv_sec and @@ one for tv_usec. I tried 0x52 before but was getting @@ EFAULT (-14) from qemu-user and no system call in strace. @@ So I think maybe qemu-user doesn't support the old select() @@ system call. @@ @@ The Linux manpage for select(2) says: @@ @@ On Linux, select() modifies timeout to reflect the @@ amount of time not slept; most other implementations do @@ not do this. (POSIX.1 permits either behavior.) This @@ causes problems both when Linux code which reads @@ timeout is ported to other operating systems, and when @@ code is ported to Linux that reuses a struct timeval @@ for multiple select()s in a loop without reinitializing @@ it. Consider timeout to be undefined after select() @@ returns. @@ @@ However, this code has no ambitions to be portable! It has @@ a Linux system call number embedded in it! .syntax unified .thumb .cpu cortex-m4 @ filthy lies, Linux can’t run on that .thumb_func .globl _start _start: bl obegin @@ First, test octal output. ldr r1, =1f bl ostr movw r1, #65535 @movs r1, #49 @ alternative test numbers @negs r1, r1 bl ooct .data 1: .asciz "65535 = 0o" 1: .asciz ". Going to call select.\n" .text ldr r1, =1b bl ostr bl oend movs r7, #0x8e @ system call number for _newselect; 0x52 fails in qemu movs r0, 1 @ selecting on one fd ldr r1, =in_fds @ that fd is in in_fds movs r2, #0 @ no output fds movs r3, #0 @ no exception fds ldr r4, =tv @ timeval for maximum wait time svc 0 @ invoke system call mov r4, r0 @ save return value bl obegin .data 1: .asciz "Called select, r0 = 0o" .text ldr r1, =1b bl ostr mov r1, r4 bl ooct .data 1: .asciz "\n" .text ldr r1, =1b bl ostr bl oend bl obegin .data 1: .asciz "Resulting input fds 0o" 2: .asciz ", tv_sec 0o" 3: .asciz ", tv_usec 0o" 4: .asciz "\n" .text ldr r1, =1b bl ostr ldr r1, =in_fds ldr r1, [r1] bl ooct ldr r1, =2b bl ostr ldr r4, =tv ldr r1, [r4] bl ooct ldr r1, =3b bl ostr ldr r1, [r4, #4] bl ooct ldr r1, =4b bl ostr bl oend movs r7, #1 @ system call number for exit movs r0, #0 @ successful exit svc 0 @ invoke system call b . @ endless loop to permit attaching a debugger if it failed @@ To output data, call obegin, then a series of calls to @@ ochar (char in r1), ostr (pointer to asciz string in r1), @@ or ooct (signed integer in r1), then oend, threading them @@ together with r0. .thumb_func obegin: ldr r0, =outbuf bx lr .thumb_func ochar: strb r1, [r0], #1 bx lr .thumb_func ostr: ldrb r2, [r1], #1 cbz r2, 1f strb r2, [r0], #1 b ostr .thumb_func oend: ldr r1, =outbuf subs r2, r0, r1 @ compute length from pointer in r0 movs r0, #1 @ stdout movs r7, #4 @ write(2) system call number svc 0 1: bx lr .thumb_func ooct: push {r4, lr} movs r4, r1 bpl 1f @ conditional to handle negative numbers movs r1, #'- bl ochar negs r1, r4 bl ooct b 2f 1: lsrs r1, r4, #3 @ set up for recursive call cbz r1, 1f @ but don’t do it if the arg would be zero bl ooct 1: ands r1, r4, #7 adds r1, #'0 bl ochar 2: pop {r4, pc} .data in_fds: .long 1 @ only select on stdin tv: .long 5 @ 5 seconds plus 0 microseconds .long 0 outbuf: .fill 1024 @ a buffer for character output