EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

linabi.htm
Enumerations
%LinSyscall64List
Macros
GetArg
GetArgCount
LinABI
StdInput
StdOutput
TerminateProgram

This file can be included to 64bit programs written in Euro Assembler.
It contains macros for access to Linux kernel 64bit ABI (Linux | Unix Application Binary Interface) using SYSCALL, as described in [SystemV].

Function arguments %1..%6 are transferred in registers RDI,RSI,RDX,R10,R8,R9, respectively.
RAX contains the function's ordinal number 0..328 from the list %LinSyscall64List.


 linabi HEAD
↑ %LinSyscall64List
Assembly-time array %LinSyscall64List declares mnemonic names assigned to Linux kernel 64bit functions, and also the required number of their arguments, as defined in documentation.
Constant prefix sys_ was removed from function names.
Functions declared with unspecified number of arguments (?) were removed or not implemented in the kernel.
Documentation
[LinSyscall64] [LinSyscall64S] [LinManSyscall]
%LinSyscall64List %SET \ Declare 64bit syscall_name(number_of_parameters)    \ numeric_id
 read(3),write(3),open(3),close(1),stat(2),fstat(2),lstat(2),poll(3),        \ 000..007
 lseek(3),mmap(6),mprotect(4),munmap(2),brk(1),rt_sigaction(4),              \ 008..013
 rt_sigprocmask(4),rt_sigreturn(1),ioctl(3),pread64(4),pwrite64(4),readv(3), \ 014..019
 writev(3),access(2),pipe(1),select(5),sched_yield(0),mremap(5),msync(3),    \ 020..026
 mincore(3),madvise(3),shmget(3),shmat(3),shmctl(3),dup(1),dup2(2),pause(0), \ 027..034
 nanosleep(2),getitimer(2),alarm(1),setitimer(3),getpid(0),sendfile(4),      \ 035..040
 socket(3),connect(3),accept(3),sendto(6),recvfrom(6),sendmsg(3),recvmsg(3), \ 041..047
 shutdown(2),bind(3),listen(2),getsockname(3),getpeername(3),socketpair(4),  \ 048..053
 setsockopt(5),getsockopt(5),clone(4),fork(0),vfork(0),execve(3),exit(1),    \ 054..060
 wait4(4),kill(2),uname(1),semget(3),semop(3),semctl(4),shmdt(1),msgget(2),  \ 061..068
 msgsnd(4),msgrcv(5),msgctl(3),fcntl(3),flock(2),fsync(1),fdatasync(1),      \ 069..075
 truncate(2),ftruncate(2),getdents(3),getcwd(2),chdir(1),fchdir(1),rename(2),\ 076..082
 mkdir(2),rmdir(1),creat(2),link(2),unlink(1),symlink(2),readlink(3),        \ 083..089
 chmod(2),fchmod(2),chown(3),fchown(3),lchown(3),umask(1),gettimeofday(2),   \ 090..096
 getrlimit(2),getrusage(2),sysinfo(1),times(1),ptrace(4),getuid(0),syslog(3),\ 097..103
 getgid(0),setuid(1),setgid(1),geteuid(0),getegid(0),setpgid(2),getppid(0),  \ 104..110
 getpgrp(0),setsid(0),setreuid(2),setregid(2),getgroups(2),setgroups(2),     \ 111..116
 setresuid(3),getresuid(3),setresgid(3),getresgid(3),getpgid(1),setfsuid(1), \ 117..122
 setfsgid(1),getsid(1),capget(2),capset(2),rt_sigpending(2),                 \ 123..127
 rt_sigtimedwait(4),rt_sigqueueinfo(3),rt_sigsuspend(2),sigaltstack(2),      \ 128..131
 utime(2),mknod(3),uselib(1),personality(1),ustat(2),statfs(2),fstatfs(2),   \ 132..138
 sysfs(3),getpriority(2),setpriority(3),sched_setparam(2),sched_getparam(2), \ 139..143
 sched_setscheduler(3),sched_getscheduler(1),sched_get_priority_max(1),      \ 144..146
 sched_get_priority_min(1),sched_rr_get_interval(2),mlock(2),munlock(2),     \ 147..150
 mlockall(1),munlockall(0),vhangup(0),modify_ldt(3),pivot_root(2),_sysctl(1),\ 151..156
 prctl(5),arch_prctl(3),adjtimex(1),setrlimit(2),chroot(1),sync(0),acct(1),  \ 157..163
 settimeofday(2),mount(5),umount2(2),swapon(2),swapoff(1),reboot(4),         \ 164..169
 sethostname(2),setdomainname(2),iopl(2),ioperm(3),create_module(?),         \ 170..174
 init_module(3),delete_module(2),get_kernel_syms(?),query_module(?),         \ 175..178
 quotactl(4),nfsservctl(?),getpmsg(?),putpmsg(?),afs_syscall(?),tuxcall(?),  \ 179..184
 security(?),gettid(0),readahead(3),setxattr(5),lsetxattr(5),fsetxattr(5),   \ 185..190
 getxattr(4),lgetxattr(4),fgetxattr(4),listxattr(3),llistxattr(3),           \ 191..195
 flistxattr(3),removexattr(2),lremovexattr(2),fremovexattr(2),tkill(2),      \ 196..200
 time(1),futex(6),sched_setaffinity(3),sched_getaffinity(3),                 \ 201..204
 set_thread_area(?),io_setup(2),io_destroy(1),io_getevents(4),io_submit(3),  \ 205..209
 io_cancel(3),get_thread_area(?),lookup_dcookie(3),epoll_create(1),          \ 210..213
 epoll_ctl_old(?),epoll_wait_old(?),remap_file_pages(5),getdents64(3),       \ 214..217
 set_tid_address(1),restart_syscall(0),semtimedop(4),fadvise64(4),           \ 218..221
 timer_create(3),timer_settime(4),timer_gettime(2),timer_getoverrun(1),      \ 222..225
 timer_delete(1),clock_settime(2),clock_gettime(2),clock_getres(2),          \ 226..229
 clock_nanosleep(4),exit_group(1),epoll_wait(4),epoll_ctl(4),tgkill(3),      \ 230..234
 utimes(2),vserver(?),mbind(6),set_mempolicy(3),get_mempolicy(5),mq_open(4), \ 235..240
 mq_unlink(1),mq_timedsend(5),mq_timedreceive(5),mq_notify(2),               \ 241..244
 mq_getsetattr(3),kexec_load(4),waitid(5),add_key(4),request_key(4),         \ 245..249
 keyctl(5),ioprio_set(3),ioprio_get(2),inotify_init(0),inotify_add_watch(3), \ 250..254
 inotify_rm_watch(2),migrate_pages(4),openat(4),mkdirat(3),mknodat(4),       \ 255..259
 fchownat(5),futimesat(3),newfstatat(4),unlinkat(3),renameat(4),linkat(5),   \ 260..265
 symlinkat(3),readlinkat(4),fchmodat(3),faccessat(3),pselect6(6),ppoll(5),   \ 266..271
 unshare(1),set_robust_list(2),get_robust_list(3),splice(6),tee(4),          \ 272..276
 sync_file_range(4),vmsplice(4),move_pages(6),utimensat(4),epoll_pwait(6),   \ 277..281
 signalfd(3),timerfd_create(2),eventfd(1),fallocate(4),timerfd_settime(4),   \ 282..286
 timerfd_gettime(2),accept4(4),signalfd4(4),eventfd2(2),epoll_create1(1),    \ 287..291
 dup3(3),pipe2(2),inotify_init1(1),preadv(5),pwritev(5),rt_tgsigqueueinfo(4),\ 292..297
 perf_event_open(5),recvmmsg(5),fanotify_init(2),fanotify_mark(5),           \ 298..301
 prlimit64(4),name_to_handle_at(5),open_by_handle_at(5),clock_adjtime(2),    \ 302..305
 syncfs(1),sendmmsg(4),setns(2),getcpu(3),process_vm_readv(6),               \ 306..310
 process_vm_writev(6),kcmp(5),finit_module(3),sched_setattr(3),              \ 311..314
 sched_getattr(4),renameat2(5),seccomp(3),getrandom(3),memfd_create(2),      \ 315..319
 kexec_file_load(5),bpf(3),stub_execveat(5),userfaultfd(1),membarrier(2),    \ 320..324
 mlock2(3),copy_file_range(6),preadv2(6),pwritev2(6),                        \ 325..328
 ;
↑ LinABI   Sys_call, Arg1,Arg2,Arg3,Arg4,Arg5,Arg6, Fastmode=No

This macroinstruction encapsulates invokation of Linux 64bit kernel functions using machine instruction SYSCALL.

Input
Sys_call is the name of invoked kernel function as specified in %LinSyscall64List enumeration, for instance read, write, open etc (case insensitive). Its ordinal number will be provided in register RAX.
Argr* are zero to six parameters (function arguments). They will be copied to registers RDI, RSI, RDX, R10, R8, R9, respectively, before SYSCALL invokation..
Fastmode=No is Boolean argument. When it's false or omitted (default), the LinABI macro preserves all registers except for RAX which returns the result of Function. Arguments in this robust mode may be provided to this macro in any GPR, regardless of the order required by ther kernel Function specification.
Fastmode=Yes is faster but it destroys registers RCX and R11 and attention must be paid to the parameter passing.
Arguments in fast mode are loaded directly to registers, starting with the last, and they may overwrite the previous contents of R9, R8, R10, RDX, RSI, RDI. Programmer should avoid using those registers for parameter passing in fast mode.
When you want to use the fast (nondefault) mode in all LinABI invokations, you don't have to append ,Fastmode=Yes to every invokation of LinABI if you set preprocessing %variable in the beginning of your program: %Fastmode %SETB Yes.
Output if Fastmode=No
RAX, RFlags as returned from kernel function, i.e. the function result, or error code when it's negative.
All other registers are preserved.
Output if Fastmode=Yes
RAX, RFlags as returned from kernel function, i.e. the function result, or error code when it's negative.
RCX,R11 are undefined.
RDI is Par1 or unchanged.
RSI is Par2 or unchanged.
RDX is Par3 or unchanged.
R10 is Par4 or unchanged.
R8 is Par5 or unchanged.
R9 is Par6 or unchanged.
Example
LinABI write, 1, =B"Hello, world!", 13 LinABI exit, 0
Documented
[LinManSyscall]
Remark

User of robust mode does not have to keep on mind that function's parameter will be loaded to registers RSI,RDI etc, overwriting their previous contents. Arguments of macro LinABI Fastmode=off may be provided in any 64bit GPR, e.g. LinABI write, stdout, RSI, RCX.
When arguments are small integers, the robust variant is sometimes shorter, because it loads registers with PUSH param + POP reg (2+1 bytes) instead of MOV reg,param (5 bytes).

The following example demonstrates both modes of LinABI on the function sys_write with three arguments: LinABI write, STDOUT_FILENO, Message, SIZE# Message |00000000: | ; Fast version. |00000000: | LinABI write, STDOUT_FILENO, Message, SIZE# Message, Fastmode=Yes |00000000:BA0E000000 + MOV RDX,14 ; Arg3 SIZE# Message. |00000005:488D350C000000 + LEA RSI,[Message] ; Arg2 OFFSET# Message, use relative addressing frame. |0000000C:BF01000000 + MOV RDI,STDOUT_FILENO ; Arg1 StdOutput handle = 1. |00000011:B801000000 + MOV RAX,1 ; Syscall write = 1. |00000016:0F05 + SYSCALL ; Perform the kernell call. |00000018: | ; LinABI in fast mode occupies 24 bytes. |00000000: | ; Robust version. |00000000: | LinABI write, STDOUT_FILENO, Message, SIZE# Message, Fastmode=No |00000000:6A0E + PUSHQ 14 ; Arg3 SIZE# Message. |00000002:488D050F000000 + LEA RAX,[Message] ; Arg2 OFFSET# Message, use relative addressing frame. |00000009:50 + PUSH RAX ; Temporary use RAX for transfer. |0000000A:6A01 + PUSH STDOUT_FILENO ; Arg1 StdOutput handle = 1. |0000000C:6A01 + PUSH 1 ; Syscall write = 1. |0000000E:6A03 + PUSH 3 ; Number of Syscall arguments = 3. |00000010:E814000000 + CALL LinABI@RT ; Invoke the system function, discard the last two pushed parameters. |00000015:5F5E5A + POP RDI,RSI,RDX ; Epilogue: restore original value of transfer registers. |00000018: | ; LinABI in robust mode occupies 24 bytes (plus 75 bytes of runtime code, once per program).

Fast mode is optimised for performance, robust mode is optimised for programmer's convenience.
LinABI %MACRO Sys_call, Arg1,Arg2,Arg3,Arg4,Arg5,Arg6, Fastmode=%Fastmode
%GPR  %SET RDI,RSI,RDX,R10,R8,R9               ; Enumerate registers for transfer of arguments.
%FnNr %SETA 0                                  ; Function identification 0..328, transferred in RAX.
FnRef %FOR %LinSyscall64List                   ; Walk through kernel function reference.
found  %IF "%Sys_call" == "%FnRef[1..%&-3]"    ; Omit the last three characters from function reference and compare.
%ArgC    %SET %FnRef[%&-1]                     ; Sys_call name was found. Pick up the digit from parenthesis ('0'..'6' or '?').
checkDef %IF "%ArgC" === "?"
           %ERROR ID=5813,%0 %Sys_call (RAX=%FnNr) is not implemented in the kernel.
           %EXITMACRO LinABI
         %ENDIF checkDef
checkArg %IF %ArgC <> %# - 1
           %ERROR ID=5811,Macro "%0 %Sys_call" requires %ArgC arguments.
           %EXITMACRO LinABI
         %ENDIF checkArg
mode     %IF %Fastmode                         ; Fast mode.
args       %WHILE %ArgC >= 1                   ; Argument passing. Start with the last one.
%Arg         %SET %*{%ArgC+1}
rel          %IF TYPE#(SEGMENT#(%Arg)) = 'A'   ; %Arg requires relocation (it's defined in a segment).
ref            %IF '%Arg[1]' === '['           ; Argument is a relocatable memory variable, e.g. [Symbol+RSI].
                 LEA %GPR{%ArgC},%Arg          ; Use relative addressing frame for relocatable %Arg.
                 MOV %GPR{%ArgC},[%GPR{%ArgC}] ; Dereference the argument value.
               %ELSE ref                       ; Argument is a relocatable immediate (pointer), e.g. Symbol.
                 LEA %GPR{%ArgC},[%Arg]        ; Use relative addressing frame for relocatable %Arg.
               %ENDIF ref
             %ELSE rel                         ; Arg is scalar, e.g. 1234, RSI, [RBP+40].
               %IF '%GPR{%ArgC}' !== '%Arg'    ; Skip if the argument already is in transfer register.
                 MOVQ %GPR{%ArgC},%Arg         ;  otherwise copy the argument to GPR.
               %ENDIF
             %ENDIF rel
%ArgC        %SETA %ArgC-1                     ; Arguments are loaded in reversed order.
           %ENDWHILE args
           MOV RAX,%FnNr                       ; Load syscall identification number %FnNr to RAX.
           SYSCALL                             ; Perform the kernell call.
           %EXITMACRO LinABI                   ; Expansion of macro is completed.
         %ELSE mode                            ; Robust mode.
ArgNr      %FOR %ArgC..1, STEP= -1             ; Push arguments, start with the last one.
%Arg         %SET %*{%ArgNr+1}
rel          %IF TYPE#(SEGMENT#(%Arg)) = 'A'   ; Argument is relocatable.
ref            %IF '%Arg[1]' === '['           ; Argument is a relocatable memory variable, e.g. [Symbol+RSI].
                 LEA %RAX,%Arg                 ; Use relative addressing frame for relocatable %Arg.
                 PUSHQ [RAX]                   ; Dereference and push the argument value.
               %ELSE ref                       ; Argument is a relocatable immediate (pointer), e.g. Symbol.
                 LEA RAX,[%Arg]                ; Use relative addressing frame for relocatable %Arg.
                 PUSH RAX                      ; Push the pointer.
               %ENDIF ref
             %ELSE rel                         ; Arg is scalar, e.g. 1234, RSI, [RBP+40].
               PUSHQ %Arg
             %ENDIF rel
           %ENDFOR ArgNr
             PUSHQ %FnNr                       ; Sys_call identification.
             PUSHQ %ArgC                       ; Number of Sys_call arguments (0..6).
           CALL LinABI@RT                      ; Runtime performs the SYSCALL and discards the last two pushed parameters.
LinABI@RT:: PROC1                              ; Robust LinABI runtime with variable number of pushed arguments.
             PUSH RCX,R11                      ; Save registers clobbered by SYSCALL.
              MOV RCX,[RSP+24]                 ; %ArgC - number of arguments on stack (0..6).
              MOV RAX,[RSP+32]                 ; %FnNr - SYSCALL function identificator.
              JRCXZ .Syscall:
              DEC CL
              XCHG RDI,[RSP+40]                ; %Arg1.
              JRCXZ .Syscall:
              DEC CL
              XCHG RSI,[RSP+48]                ; %Arg2.
              JRCXZ .Syscall:
              DEC CL
              XCHG RDX,[RSP+56]                ; %Arg3.
              JRCXZ .Syscall:
              DEC CL
              XCHG R10,[RSP+64]                ; %Arg4.
              JRCXZ .Syscall:
              DEC CL
              XCHG R8,[RSP+72]                 ; %Arg5.
              JRCXZ .Syscall:
              DEC CL
              XCHG R9,[RSP+80]                 ; %Arg6.
.Syscall:     SYSCALL
             POP R11,RCX                       ; Restore registers clobbered by SYSCALL.
             RET 2*8                           ; Discard %ArgC and %FnNr.
            ENDP1 LinABI@RT::                  ; Pushed arguments will be discarded by LinABI's epilogue.
           POP %GPR{1..%ArgC}                  ; Epilogue: restore original value of transfer registers.
           %EXITMACRO LinABI                   ; Expansion of macro is completed.
         %ENDIF mode
       %ENDIF found
       %FnNr %SETA %FnNr+1                     ; Try the next function reference in %LinSyscall64List.
      %ENDFOR FnRef
      %ERROR ID=5812,Unrecognized function name "%Sys_call". See %%LinSyscall64List in "linapi.htm".
    %ENDMACRO LinABI
↑ GetArg   ArgNumber, Frame=RSP
Macro GetArg retrieves ArgNumber-th parameter provided on command line.
Parameters on the command line are separated with unquoted white space(s).
Single or double quotes are not returned.
Input
ArgNumber is ordinal number of the required parameter (0..127). The 0-th parameter specifies the executable file itself. ArgNr can be an immediate number, 64bit GPR or memory variable.
Frame=RSP specifies the pointer to process stack, i.e. to the DWORD with process' argc value.
The default Frame=RSP is valid only if nothing has been pushed yet since the program started. Otherwise use something like Frame=RSP+8, Frame=RBP+16 etc.
Output
CF=0,
RSI is pointer to the first byte of the requested argument,
RCX is argument size in bytes.
Error
CF=1 the frame is wrong or if requested argument was not provided.
RCX=0
RSI=unchanged.
See also
GetArgCount
Process' stack layout
of a program launched as ./executable --option argumentA argumentB ┌────────┐ │ 0 │ NULL QWORD which terminates array of pointers to env strings. ├────────┤ │ env2 │ Pointer to 2nd ASCIIZ environment string. ├────────┤ │ env1 │ Pointer to 1st ASCIIZ environment string. ├────────┤ │ 0 │ NULL QWORD which terminates array of pointers to arg strings. ├────────┤ │ argv3 │ Pointer to ASCIIZ string argumentB. ├────────┤ │ argv2 │ Pointer to ASCIIZ string argumentA. ├────────┤ │ argv1 │ Pointer to ASCIIZ string --option. ├────────┤ │ execut │ Pointer to this executable file name ./executable. ├────────┤ │ argc │ Number of arguments including the executable itself 4. Frame-> └────────┘
GetArg %MACRO ArgNumber, Frame=RSP
     LEA RCX,[%Frame]
     PUSHQ %ArgNumber
     CALL GetArgLin64@RT
GetArgLin64@RT:: PROC1 ; Stdcalled with Param=ArgNumber, RCX=%Frame.
    PUSH RAX,RBX,RDX,RDI
     MOV RSI,RCX       ; Frame.
     MOV RBX,[RSP+40]  ; Requested ArgNumber (0..126) or -1.
     SUB EDX,EDX
     MOV RCX,[RSI]     ; ArgC (1..127).
     CMP RBX,-1        ; Test if GetArg was invoked from GetArgCount.
     JNE .50:
     DEC RCX           ; Do not count the executable itself.
     JMP .90:
.Error:XOR ECX,ECX
     STC
     JMP .90:
.50: CMP EBX,126
     JA .Error:
     CMP ECX,EDX
     JZ .Error:        ; Invalid argc, bad %Frame provided.
     CMP ECX,127
     JA .Error:
     CMP EBX,ECX
     JNB .Error:       ; This many arguments are not available.
     MOV RDI,[RSI+8*RBX+8]
     TEST RDI
     JZ  .Error:       ; Invalid %Frame.
     MOV RSI,RDI
     XOR ECX,ECX
     DEC RCX
     REPNE SCASB       ; Find the zero terminator, set CF=0.
     NOT RCX
     DEC ECX
.90:POP RDI,RDX,RBX,RAX
    RET 1*8
  ENDP1 GetArgLin64@RT
 %ENDMACRO GetArg
↑ GetArgCount Frame=RSP
returns number of arguments provided on the command line of the executed program. Arguments are separated with unquoted space(s).
Input
is taken from the command line which launched the program.
Frame=RSP specifies the pointer to process stack, i.e. to the QWORD with process' argc value.
The default Frame=RSP is valid only if nothing has been pushed yet since the program started. Otherwise use something like Frame=RSP+8, Frame=RBP+16 etc.
Output
CF=0
RCX=number of arguments on the command line which launched the program (0..127).
Error
CF=1 if the Frame= was invalid.
Depends on
GetArg
GetArgCount %MACRO Frame=RSP
     GetArg -1, Frame=%Frame
   %ENDMACRO GetArgCount
↑ StdOutput String1, String2,,, Size=-1, Handle=1, Eol=No

Macro StdOutput writes one or more concatenated strings to the standard output or to other device or file specified with the Handle identifier.

Strings are either zero-terminated, or the keyword Size= must specify their size in bytes. The terminating NUL character is never written.

If keyword Eol=Yes, macro writes LF after all strings.

Input
StringX is pointer to the buffer with characters-to-be-written.
Size=-1 is the maximal possible string size in bytes. If its left to -1 (default), strings must be zero-terminated. This parameter applies to all ordinal operands.
Handle=1 is the Linux file descriptor. Possible values are defined in linsfile.htm: Eol=No. When this Boolean keyword is switched on, an additional character LF (0x10) will be written on output after all strings have been written.
Output
CF=0. All registers are preserved.
Error
CF=1 when SYSCALL returned an error.
Depends on
LinABI
Examples
StdOutput TextPart1,TextPart2,TextPart3 StdOutput Eol=Yes ; Write new line (LF) only. StdOutput ="Error writing to file ",FileName, Handle=STDERR_FILENO
StdOutput %MACRO  String1,String2,,,Size=-1, Handle=1, Eol=No
opN %FOR 1..%#, STEP=1                ; Walk through all ordinal operands.
      PUSHQ %Handle, %Size
rel   %IF TYPE#(SEGMENT#(%1)) = 'A'   ; String is relocatable.
ref     %IF '%1[1]' === '['           ; Pointer reference, e.g. [ArrayOfPointersToMsgs+RSI].
          PUSH RAX
          LEA RAX,%1
          MOV RAX,[RAX]               ; Dereference the pointer.
          XCHG RAX,[RSP]
        %ELSE ref                     ; Absolute reference, e.g. Message.
          PUSH RAX
          LEA RAX,[%1]
          XCHG RAX,[RSP]
        %ENDIF ref
      %ELSE rel                       ; String is not relocatable, e.g. RSI or [RBP+16].
        PUSHQ %1
      %ENDIF rel
      CALL StdOutputLin64@RT
      %SHIFT 1                        ; The next string to write.
    %ENDFOR opN
eol %IF %Eol
       PUSHQ %Handle, 1, 0            ; NUL string pointer represents the request for LF.
       CALL StdOutputLin64@RT
     %ENDIF eol
StdOutputLin64@RT:: PROC1             ; StdCalled runtime with params String, Size, Handle.
     PUSH RAX,RBX,RCX,RSI,RDI,R11
     PUSHQ 0x0A                       ; Prepare Eol character on stack.
       MOV RBX,[RSP+80]               ; File descriptor %Handle.
       MOV RCX,[RSP+72]               ; String maximal %Size.
       MOV RDI,[RSP+64]               ; String pointer or 0 for Eol.
       XOR EAX,EAX
       CMP RDI,RAX                    ; NULL pointer in RDI signalizes Eol request.
       JNE .10:
       INC RDI                        ; Size of Eol=1.
       MOV RSI,RSP                    ; Pointer to Eol (0x0A).
       JMP .50:
.10:   MOV RSI,RDI                    ; Remember the start of string in RSI.
       REPNE SCASB                    ; Find the end of string.
       JNE .30:
       DEC RDI                        ; Omit the NUL terminator.
.30:   SUB RDI,RSI                    ; Netto string is now ESI,EDI
.50:   LinABI write,RBX,RSI,RDI, Fastmode=No
       SAL RAX                        ; Copy SF to CF (this signalizes an error).
.90: POP RAX,R11,RDI,RSI,RCX,RBX,RAX
     RET 3*8
  ENDP1 StdOutputLin64@RT::
 %ENDMACRO StdOutput
↑ StdInput Buffer, Size=, Handle=0

Macro StdInput reads from standard input specified by the Handle.

Input
Buffer is offset of memory where the input line will be stored.
Size= is the Buffer size. If omitted (default), macro will use SIZE# attribute of the Buffer.
Handle=0 is the Linux file descriptor. Possible values are defined in linsfile.htm:
Output
CF=0, RCX=number of bytes read.
Error
CF=1, RCX=error code.
Example
StdInput RSI, Size=80
StdInput %MACRO Buffer, Size=, Handle=0
    PUSHQ %Handle
bs  %IF "%Size" === ""
      PUSHQ SIZE# %Buffer
    %ELSE bs
      PUSHQ %Size
    %ENDIF bs
rel %IF TYPE#(SEGMENT#(%Buffer)) = 'A' ; Buffer is relocatable.
ref   %IF "%Buffer[1]" === "["   ; Pointer reference, e.g. [ArrayOfPointersToBuffers+RSI].
        LEA RCX,%Buffer
        MOV RCX,[RCX]            ; Dereference the pointer.
        PUSH RCX
      %ELSE ref                  ; Absolute reference, e.g. InputLine.
        LEA RCX,[%Buffer]
        PUSH RCX
      %ENDIF ref
    %ELSE rel                    ; Buffer is not relocatable, e.g. RBX or [RBP+16].
      PUSHQ %Buffer
    %ENDIF
    CALL StdInputLin64@RT
StdInputLin64@RT::PROC1          ; StdCalled with params Handle, BufferSize, BufferPtr.
    PUSH RAX,RDX,RSI,RDI,R8,R9,R10,R11
      MOV RSI,[RSP+72]           ; %Buffer.
      MOV RDX,[RSP+80]           ; %Size.
      MOV RDI,[RSP+88]           ; %Handle.
      LinABI read,RDI,RSI,RDX, Fastmode=Yes
      MOV RCX,RAX
      SAL RAX                    ; Copy SF to CF (this signalizes an error).
    POP R11,R10,R9,R8,RDI,RSI,RDX,RAX
    RET 3*8
   ENDPROC1 StdInputLin64@RT::
 %ENDMACRO StdInput
↑ TerminateProgram Errorlevel=0
This macro provides exit from the running process and return to the operating system.
It also specifies the Errorlevel (plain number) which can be used to inform the batch script which launched the program whether the program terminated normally or due to some error condition.
Input
Errorlevel= is the return code of the terminating program.
Beside the keyword Errorlevel=, this value may also be specified as an ordinal operand.
When this argument is omitted, it defaults to 0.
Output
is not applicable.
Example
TerminateProgram Errorlevel=[WorstErrLevel] ; Keyword value (from memory). TerminateProgram 8 ; Ordinal value.
TerminateProgram %MACRO Errorlevel=0
     PUSHQ 60            ; Function sys_exit identification.
     %IF %# = 1          ; If %Errorlevel is provided as ordinal value.
       PUSHQ %1
     %ELSE               ; %Errorlevel is provided as keyword.
       PUSHQ %Errorlevel
     %ENDIF
     POP RDI
     POP RAX
     SYSCALL
   %ENDMACRO TerminateProgram
  ENDHEAD linabi

▲Back to the top▲