EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

linapi.htm
Enumerations
%LinSyscall32List
Macros
GetArg
GetArgCount
LinAPI
StdInput
StdOutput
TerminateProgram

This file can be included to 32bit Linux programs written in EuroAssembler.
It declares macroinstructions for interaction with Linux kernel 32bit Application Programming Interface which uses INT 0x80 to invoke core function of operating system.

Access method INT 0x80 always invokes the 32bit interface, regardless if it is called from 32bit or 64bit mode. On 64bit system this will fail if the kernel was compiled without flag CONFIG_IA32_EMULATION.

Function arguments %1..%6 are transferred in registers EBX,ECX,EDX,ESI,EDI,EBP, respectively.
EAX contains the function's ordinal number 0..337 from the list %LinSyscall32List.


 linapi HEAD
↑ %LinSyscall32List
Assembly-time array %LinSyscall32List declares mnemonic names assigned to Linux kernel 32bit functions, and also the required number of their arguments, as specified in documentation.
Documentation
[LinSyscall32] [LinManSyscall]
%LinSyscall32List %SET \ Declare 32bit syscall_name(number_of_parameters).
 restart_syscall(0),exit(1),fork(1),read(3),write(3),                        \ 000..004
 open(3),close(1),waitpid(3),creat(2),link(2),                               \ 005..009
 unlink(1),execve(4),chdir(1),time(1),mknod(3),                              \ 010..014
 chmod(2),lchown16(3),17(0),stat(2),lseek(3),                                \ 015..019
 getpid(0),mount(5),oldumount(1),setuid16(1),getuid16(0),                    \ 020..024
 stime(1),ptrace(4),alarm(1),fstat(2),pause(0),                              \ 025..029
 utime(2),31(0),32(0),access(2),nice(1),                                     \ 030..034
 35(0),sync(0),kill(2),rename(2),mkdir(2),                                   \ 035..039
 rmdir(1),dup(1),pipe(1),times(1),44(0),                                     \ 040..044
 brk(1),setgid16(1),getgid16(0),signal(2),geteuid16(0),                      \ 045..049
 getegid16(0),acct(1),umount(2),53(0),ioctl(3),                              \ 050..054
 fcntl(3),56(0),setpgid(2),58(0),olduname(1),                                \ 055..059
 umask(1),chroot(1),ustat(2),dup2(2),getppid(0),                             \ 060..064
 getpgrp(0),setsid(0),sigaction(3),sgetmask(0),ssetmask(1),                  \ 065..069
 setreuid16(2),setregid16(2),sigsuspend(3),sigpending(1),sethostname(2),     \ 070..074
 setrlimit(2),old_getrlimit(2),getrusage(2),gettimeofday(2),settimeofday(2), \ 075..079
 getgroups16(2),setgroups16(2),old_select(1),symlink(2),lstat(2),            \ 080..084
 readlink(3),uselib(1),swapon(2),reboot(4),old_readdir(2),                   \ 085..089
 old_mmap(1),munmap(2),truncate(2),ftruncate(2),fchmod(2),                   \ 090..094
 fchown16(3),getpriority(2),setpriority(3),98(0),statfs(2),                  \ 095..099
 fstatfs(2),ioperm(3),socketcall(2),syslog(3),setitimer(3),                  \ 100..104
 getitimer(2),newstat(2),newlstat(2),newfstat(2),uname(1),                   \ 105..109
 iopl(2),vhangup(0),111(0),vm86old(2),wait4(4),                              \ 110..114
 swapoff(1),sysinfo(1),ipc(0),fsync(1),sigreturn(1),                         \ 115..119
 clone(5),setdomainname(2),newuname(1),modify_ldt(3),adjtimex(1),            \ 120..124
 mprotect(3),sigprocmask(3),127(0),init_module(3),delete_module(2),          \ 125..129
 130(0),quotactl(4),getpgid(1),fchdir(1),bdflush(2),                         \ 130..134
 sysfs(3),personality(1),137(0),setfsuid16(1),setfsgid16(1),                 \ 135..139
 llseek(5),getdents(3),select(5),flock(2),msync(3),                          \ 140..144
 readv(3),writev(3),getsid(1),fdatasync(1),sysctl(1),                        \ 145..149
 mlock(2),munlock(2),mlockall(1),munlockall(0),sched_setparam(2),            \ 150..154
 sched_getparam(2),sched_setscheduler(3),sched_getscheduler(1),              \ 155..157
 sched_yield(0),sched_get_priority_max(1),                                   \ 158..159
 sched_get_priority_min(1),sched_rr_get_interval(2),nanosleep(2),mremap(5),  \ 160..163
 setresuid16(3),getresuid16(3),vm86(3),167(0),poll(3),nfsservctl(3),         \ 164..169
 setresgid16(3),getresgid16(3),prctl(5),rt_sigreturn(1),sigaction(4),        \ 170..174
 sigprocmask(4),sigpending(2),sigtimedwait(4),sigqueueinfo(3),sigsuspend(2), \ 175..179
 pread64(4),pwrite64(4),chown16(3),getcwd(2),capget(2),                      \ 180..184
 capset(2),sigaltstack(3),sendfile(4),188(0),189(0),                         \ 185..189
 vfork(1),getrlimit(2),nmap_pgoff(0),truncate64(2),ftruncate64(2),           \ 190..194
 stat64(2),lstat64(2),fstat64(2),lchown(3),getuid(0),                        \ 195..199
 getgid(0),geteuid(0),getegid(0),setreuid(2),setregid(2),                    \ 200..204
 getgroups(2),setgroups(2),fchown(3),setresuid(3),getresuid(3),              \ 205..209
 setresgid(3),getresgid(3),chown(3),setuid(1),setgid(1),                     \ 210..214
 setfsuid(1),setfsgid(1),pivot_root(2),mincore(3),madvise(3),                \ 215..219
 getdents64(3),fcntl64(3),222(0),223(0),gettid(0),                           \ 220..224
 readahead(3),setxattr(5),lsetxattr(5),fsetxattr(5),getxattr(4),             \ 225..229
 lgetxattr(4),fgetxattr(4),listxattr(3),llistxattr(3),flistxattr(3),         \ 230..234
 removexattr(2),lremovexattr(2),fremovexattr(2),tkill(2),sendfile64(4),      \ 235..239
 futex(0),sched_setaffinity(3),sched_getaffinity(3),set_thread_area(1),      \ 240..243
 get_thread_area(1),io_setup(2),io_destroy(1),io_getevents(5),io_submit(3),  \ 244..248
 io_cancel(3),fadvise64(4),251(0),exit_group(1),lookup_dcookie(3),           \ 249..253
 epoll_create(1), epoll_ctl(4),epoll_wait(4),remap_file_pages(5),            \ 254..257
 set_tid_address(1),timer_create(3),timer_settime(4),timer_gettime(2),       \ 258..261
 timer_getoverrun(1),timer_delete(1),clock_settime(2),clock_gettime(2),      \ 262..265
 clock_getres(2),clock_nanosleep(4),statfs64(3),fstatfs64(2),                \ 266..269
 tgkill(3),utimes(2),fadvise64_64(4),273(0),mbind(0),                        \ 270..274
 get_mempolicy(5),set_mempolicy(3),mq_open(4),mq_unlink(1),mq_timedsend(5),  \ 275..279
 mq_timedreceive(5),mq_notify(2),mq_getsetattr(3),kexec_load(4),waitid(5),   \ 280..284
 285(0),add_ket(5),request)key(4),keyctl(5),ioprio_set(3),                   \ 285..289
 ioprio_get(2),inotify_init(0),inotify_add_watch(3),inotify_rm_watch(2),     \ 290..293
 migrate_pages(4),openat(4),mkdirat(4),mknodat(4),fchownat(5),futimesat(3),  \ 294..299
 fstatat64(4),unlinkat(3),renameat(4),linkat(5),symlinkat(3),                \ 300..304
 readlinkat(4),fchmodat(3),faccessat(3),pselect6(0),ppoll(5),                \ 305..309
 unshare(1),set_robust_list(2),get_robust_list(3),splice(0),                 \ 310..313
 sync_file_range(4),tee(4),vmsplice(4),move_pages(0),getcpu(3),              \ 314..318
 epoll_pwait(0),utimensat(4),signalfd(3),timerfd_create(2),eventfd(1),       \ 319..323
 fallocate(4),timerfd_settime(4),timerfd_gettime(2),signalfd4(3),            \ 324..327
 eventfd2(2),epoll_create1(1),dup3(3),pipe2(2),inotify_init1(1),preadv(5),   \ 328..333
 pwritev(5),rt_tgsigqueueinfo(4),perf_event_open(5),recvmmsg(5),             \ 334..337
 ;
↑ LinAPI   Sys_call, Arg1,Arg2,Arg3,Arg4,Arg5,Arg6, Fastmode=No

This macroinstruction encapsulates invokation of Linux 32bit kernel functions using machine instruction INT 0x80.

Input
Sys_call is the name of invoked kernel function as specified in %LinSyscall32List enumeration, for instance exit, fork, read etc (case insensitive). Its ordinal number will be provided in register EAX.
Arg* are zero to six function arguments. They will be copied to registers EBX, ECX, EDX, ESI, EDI, EBP, respectively.
Fastmode=No is Boolean argument. When it's false or omitted (default), the LinAPI macro preserves all registers except for EAX which returns the result of Sys_call. Arguments in this robust mode may be provided to this macro in any GPR, regardless of the order required by INT 0x80 specification.
Fastmode=Yes is faster but attention must be paid to the parameter passing. Macro LinAPI in this fast mode loads arguments directly to their registers, starting with the last, and they may overwrite the previous contents of EBP, EDI, ESI, EDX, ECX, EBX.
When you want to use the fast (nondefault) mode in all LinAPI invokations, you don't have to append ,Fastmode=Yes to every invokation of this macro if you set preprocessing %variable in the beginning of the program: %Fastmode %SETB Yes.
Output if Fastmode=No
EFlags and EAX contain the result value of function, or error code when EAX is negative.
All other GP registers are preserved.
Output if Fastmode=Yes
EFlags and EAX contain the result value of function, or error code when EAX is negative.
ECX,EDX are undefined.
EBX is Param1 or unchanged.
ESI is Param4 or unchanged.
EDI is Param5 or unchanged.
EBP is Param6 or unchanged.
Example
LinAPI write,1,=B"Hello, world!",13 LinAPI exit,0
Documented
[LinManSyscall]
Remark

User of default robust mode (Fastmode=off ) does not have to keep on mind that function's parameter will be loaded to registers EBX, ECX, EDX etc, overwriting their previous contents. Arguments of macro may be provided in any 32bit GPR, e.g. LinAPI write, STDOUT_FILENO, ESI, ECX.
And the robust variant is often 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 LinAPI invoking the function mount with five arguments: LinAPI mount, =B"/dev/fda", =B"/mount/a", 0, MS_RDONLY, NUL |00000000: | ; Fast version. |00000000: | LinAPI mount,=B"/dev/fda",=B"/mount/a",0,MS_RDONLY,NUL, Fastmode=Yes |00000000:BF00000000 + MOV EDI,NUL ; Load 5th parameter: pointer to data. |00000005:BE01000000 + MOV ESI,MS_RDONLY ; Load 4th parameter: mounting flags. |0000000A:BA00000000 + MOV EDX,0 ; Load 3rd parameter: filesystem type. |0000000F:B9[20000000] + MOV ECX,=B"mount/a" ; Load 2nd parameter: directory. |00000014:BB[29000000] + MOV EBX,=B"/dev/fda" ; Load 1st parameter: device. |00000019:B815000000 + MOV EAX,mount ; Load function identification. |0000001E:CD80 + INT 0x80 ; Invoke the system function. |00000020: | ; LinAPI in fast mode occupies 32 bytes of code. |00000000: | ; Robust version. |00000000: | LinAPI mount,=B"/dev/fda",=B"/mount/a",0,MS_RDONLY,NUL, Fastmode=No |00000000:60 + PUSHAD ; Save all registers. |00000001:6A15 + PUSHD mount ; Function identification: mount. |00000003:68[20000000] + PUSHD =B"/dev/fda" ; 1st parameter: device. |00000008:68[29000000] + PUSHD =B"mount/a" ; 2nd parameter: directory. |0000000D:6A00 + PUSHD 0 ; 3rd parameter: filesystem type. |0000000F:6A01 + PUSHD MS_RDONLY ; 4th parameter: mounting flags. |00000011:6A00 + PUSHD NUL ; 5th parameter: pointer to data. |00000013:5F + POP EDI ; Load 5th parameter. |00000014:5E + POP ESI ; Load 4th parameter. |00000015:5A + POP EDX ; Load 3rd parameter. |00000016:59 + POP ECX ; Load 2nd parameter. |00000017:5B + POP EBX ; Load 1st parameter. |00000018:58 + POP EAX ; Load function identification. |00000019:CD80 + INT 0x80 ; Invoke the system function. |0000001B:8944241C + MOV [ESP+28],EAX ; Prepare returned value to [%ReturnEAX]. |0000001F:61 + POPAD ; Restore all registers but EAX. |00000020: | ; LinAPI in robust mode occupies 32 bytes of code.

Fast mode is optimised for performance, robust mode is optimised for programmer's convenience.
LinAPI %MACRO Sys_call, Arg1,Arg2,Arg3,Arg4,Arg5,Arg6, Fastmode=%Fastmode
%GPR  %SET EBX,ECX,EDX,ESI,EDI,EBP                ; Enumerate registers for transfer of arguments.
%FnNr %SETA 0                                     ; Function identification 0..337, transferred in EAX.
FnRef %FOR %LinSyscall32List                      ; Walk thru kernel function declarations.
found   %IF "%Sys_call" == "%FnRef[1..%&-3]"      ; Omit the last three characters from function reference declaration and compare.
%ArgC     %SETA %FnRef[%&-1]                      ; Sys_call name was found. Pick up the digit from parenthesis ('0'..'6').
checkArg  %IF %ArgC <> %# - 1
            %ERROR ID=5811,Macro "%0 %Sys_call" requires %ArgC arguments.
            %EXITMACRO LinAPI
          %ENDIF checkArg
mode      %IF %Fastmode                           ; Fast mode.
params      %WHILE %ArgC > 0
              %IF "%GPR{%ArgC}" !== "%*{%ArgC+1}" ; Skip if the argument already is in transfer register.
                MOV %GPR{%ArgC},%*{%ArgC+1}       ;  otherwise copy the parameter to GPR.
              %ENDIF
%ArgC         %SETA %ArgC-1                       ; Repeat with the previous parameter.
            %ENDWHILE params
            MOV EAX,%FnNr                         ; Load Sys_call's identification number.
            INT 0x80                              ; Perform the kernel call.
            %EXITMACRO LinAPI                     ; Stop further search in %LinSyscall32List.
          %ELSE mode                              ; Robust mode.
            PUSHAD                                ; Save all registers.
            PUSHD %FnNr                           ; Push Function's identificator (0..337).
atleast1    %IF %# > 1                            ; If the Function expects more then 0 parameters.
              PUSHD %*{2..}                       ; Push all arguments on stack in nominal order.
popPars       %WHILE %ArgC > 0
                POP %GPR{%ArgC}                   ; Pop all arguments from stack to their transfer registers.
%ArgC           %SETA %ArgC-1                     ; Arguments are popped in reversed order.
              %ENDWHILE popPars
            %ENDIF atleast1
            POP EAX                               ; Load function identification number %FnNr to EAX.
            INT 0x80                              ; Perform the kernel call.
            MOV [ESP+28],EAX                      ; Copy the Function result to [%ReturnEAX].
            POPAD                                 ; Restore all registers with updated EAX and EFlags.
            %EXITMACRO LinAPI                     ; Stop further search in %LinSyscall32List.
          %ENDIF mode
        %ENDIF found                              ; Otherwise continue search.
%FnNr   %SETA %FnNr+1                             ; Try the next function reference in %LinSyscall32List.
      %ENDFOR FnRef
      %ERROR ID=5812,Unrecognized syscall name "%Sys_call". See %%LinSyscall32List in "linapi.htm".
    %ENDMACRO LinAPI
↑ GetArg   ArgNumber, Frame=ESP
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, 32bit GPR or memory variable.
Frame=ESP specifies the pointer to process stack, i.e. to the DWORD with process' argc value.
The default Frame=ESP is valid only if nothing has been pushed yet since the program started. Otherwise use something like Frame=ESP+4, Frame=EBP+12 etc.
Output
CF=0,
ESI is pointer to the first byte of the requested argument,
ECX is argument size in bytes.
Error
CF=1 the frame is wrong or if requested argument was not provided.
ECX=0
ESI=unchanged.
See also
GetArgCount
Example
GetArg 1
Process' stack layout of a program executable launched from console as ./executable --option argumentA argumentB
┌────────┐ │ 0 │ NULL DWORD which terminates array of pointers to env strings. ├────────┤ │ env2 │ Pointer to 2nd ASCIIZ environment string. ├────────┤ │ env1 │ Pointer to 1st ASCIIZ environment string. ├────────┤ │ 0 │ NULL DWORD 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=ESP
     LEA ECX,[%Frame]
     PUSHD ECX, %ArgNumber
     CALL GetArgLin32@RT
GetArgLin32@RT:: PROC1 ; Stdcalled with %Param1=ArgNumber, Param2=Frame.
    PUSHAD
     MOV EBP,ESP
     MOV ESI,[%Param2] ; Frame.
     MOV EBX,[%Param1] ; Requested ArgNumber (0..126) or -1.
     SUB EDX,EDX
     MOV ECX,[ESI]     ; argc (1..127).
     CMP EBX,-1        ; Test if GetArg was invoked from GetArgCount.
     JNE .50:
     DEC ECX           ; Do not count the executable itself.
     JMP .80:
.Error:STC
     JMP .80:
.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 EDI,[ESI+4*EBX+4]
     TEST EDI
     JZ  .Error:       ; Invalid %Frame.
     MOV [%ReturnESI],EDI
     XOR ECX,ECX
     DEC ECX
     REPNE SCASB       ; Find the zero terminator, set CF=0.
     NOT ECX
     DEC ECX
.80: MOV [%ReturnECX],ECX ; Argument size without the terminating zero.
.90:POPAD
    RET 2*4
  ENDP1 GetArgLin32@RT
 %ENDMACRO GetArg
↑ GetArgCount Frame=ESP
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=ESP specifies the pointer to process stack, i.e. to the DWORD with process' argc value.
The default Frame=ESP is valid only if nothing has been pushed yet since the program started. Otherwise use something like Frame=ESP+4, Frame=EBP+12 etc.
Output
CF=0
ECX=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=ESP
     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 to output.

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

Input
String* is pointer to the buffer with characters-to-be-written.
Size=-1 is the maximal possible string size in bytes. If it is 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 INT 0x80 returned an error.
Depends on
LinAPI
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
OpNr %FOR 1..%#, STEP=1    ; Walk through all ordinal operands.
       PUSHD %Handle, %Size, %1
       CALL StdOutputLin32@RT
       %SHIFT 1            ; The next string to write.
     %ENDFOR OpNr
eol  %IF %Eol
       PUSHD %Handle, 1, 0 ; NUL string pointer is the request for LF.
       CALL StdOutputLin32@RT
     %ENDIF eol
StdOutputLin32@RT:: PROC1
     PUSHAD
     PUSHD 0x0A            ; Prepare Eol character on stack.
       MOV EBX,[ESP+48]    ; File descriptor %Handle.
       MOV ECX,[ESP+44]    ; String maximal %Size.
       MOV EDI,[ESP+40]    ; String pointer or 0 for Eol.
       XOR EAX,EAX
       CMP EDI,EAX
       JNZ  .10:           ; NULL pointer signalizes Eol request.
       INC EDI             ; Size of Eol=1.
       MOV ESI,ESP         ; Pointer to Eol (0x0A).
       JMP .50:
.10:   MOV ESI,EDI
       REPNE SCASB         ; Find the end of string.
       JNE .30:
       DEC EDI             ; Skip the NUL terminator.
.30:   SUB EDI,ESI         ; Netto string is now ESI,EDI
.50:   LinAPI write,EBX,ESI,EDI, Fastmode=Yes
       SAL EAX             ; Copy SF to CF (this signalizes an error).
.90: POP EAX
     POPAD
     RET 3*4
  ENDP1 StdOutputLin32@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, ECX=number of bytes read.
Error
CF=1, ECX=error code.
Example
StdInput ESI, Size=80
StdInput %MACRO Buffer, Size=, Handle=0
    %IF "%Size" === ""
      PUSHD SIZE# %Buffer, %Buffer, %Handle
    %ELSE
      PUSHD %Size, %Buffer, %Handle
    %ENDIF
    CALL StdInputLin32@RT
StdInputLin32@RT::PROC1 ; StdCalled with params Handle, BufferPtr, BufferSize.
    PUSHAD
      MOV EBP,ESP
      LinAPI read,[%Param1],[%Param2],[%Param3], Fastmode=On
      MOV [%ReturnECX],EAX
      SAL EAX           ; Copy SF to CF (this signalizes an error).
.90:POPAD
    RET 3*4
   ENDPROC1 StdInputLin32@RT::
 %ENDMACRO StdInput
↑ TerminateProgram Errorlevel=0
This macro provides exit from the running process and returns 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
     %IF %#=1            ; If ordinal operand was provided.
       PUSHD %1
     %ELSE
       PUSHD %Errorlevel ; If keyword operand was provided.
     %ENDIF
     POP EBX
     LinAPI exit,EBX, Fastmode=On
   %ENDMACRO TerminateProgram
   ENDHEAD linapi

▲Back to the top▲