This file can be included to 32bit Linux programs written in EuroAssembler.
It declares macroinstructions for some basic OS interactions:
retrieving of environment and command-line arguments, standard I/O, program termination, and
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 to INT 0x80
in registers EBX,ECX,EDX,ESI,EDI,EBP
, respectively.
EAX
contains the function's ordinal number 0..337 from the list
%LinSyscall32List.
linapi HEAD
%Param6 %SET EBP+56 %Param5 %SET EBP+52 %Param4 %SET EBP+48 %Param3 %SET EBP+44 %Param2 %SET EBP+40 %Param1 %SET EBP+36 %ReturnEAX %SET EBP+28 %ReturnECX %SET EBP+24 %ReturnEDX %SET EBP+20 %ReturnEBX %SET EBP+16 %ReturnESP %SET EBP+12 %ReturnEBP %SET EBP+08 %ReturnESI %SET EBP+04 %ReturnEDI %SET EBP+00
The most reliable source of system call numbers seems the header file/usr/include/asm/unistd.hor/usr/include/asm/unistd_32.h.
%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 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 ;
This macroinstruction encapsulates invokation of Linux 32bit kernel functions
using machine instruction INT 0x80
.
exit
, fork
, read
etc (case insensitive).
Its ordinal number will be provided in register EAX.
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
.
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.
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
argc
value. It can be GPR or [DWORD_memory_variable].
Frame=ESP
is valid only if nothing has been pushed yet
since the program started. Otherwise use something like
LEA ECX,[ESP+4]
or LEA ECX,[EBP+8]
and then Frame=ECX
.
executable
launched from console as
./executable --option argumentA argumentB
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 PUSHD %Frame, %ArgNumber CALL GetArgLin32@RT GetArgLin32@RT:: PROC1 ; Stdcalled with %Param1=ArgNumber, %Param2=Frame. PUSHAD MOV EBP,ESP MOV EBX,[%Param1] ; Requested ArgNumber (0..127) or -1. MOV ESI,[%Param2] ; ^Frame. SUB EAX,EAX MOV ECX,[ESI] ; argc (expected 1..127). MOV [%ReturnECX],EAX DEC ECX ; Do not count the executable name itself. CMP EBX,-1 ; Test if GetArg was invoked from GetArgCount. JE .80: MOV EAX,EBX OR EAX,ECX TEST EAX,0xFFFF_FF80 ; Both EBX=ArgNumber and ECX=argc-1 should not exceed 127. STC JNZ .90: CMP EBX,ECX JA .90: ; This many arguments are not available, return with ECX=0. MOV EDI,[ESI+4*EBX+4] TEST EDI STC JZ .90: ; Invalid %Frame. MOV [%ReturnESI],EDI XOR ECX,ECX XOR EAX,EAX NOT 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
argc
value. It can be GPR or [DWORD_memory_variable].
Frame=ESP
is valid only if nothing has been pushed yet
since the program started. Otherwise use something like
LEA ECX,[ESP+4]
or LEA ECX,[EBP+8]
and then Frame=ECX
.GetArgCount %MACRO Frame=ESP GetArg -1, Frame=%Frame %ENDMACRO GetArgCount
Macro PutArg retrieves ArgNumber-th argument from command-line, copies its content to the memory specified by BufPtr, BufSize and appends one NUL character at its end.
SIZE# %BufPtr
will be used instead.
argc
value. It can be GPR or [DWORD_memory_variable].
Frame=ESP
is valid only if nothing has been pushed yet
since the program started. Otherwise use something like
LEA ECX,[ESP+4]
or LEA ECX,[EBP+8]
and then Frame=ECX
.PutArg %MACRO ArgNumber, BufPtr, BufSize, Frame=ESP sized? %IF %# = 2 mem? %IF %^PASS > 1 && TYPE#(SEGMENT# %BufPtr) != 'A' %ERROR ID=5814, 'Please specify the size of output buffer.' %EXITMACRO PutEnv %ELSE mem? ; BufPtr is specified as a memory variable with size. %PutArgSize %SETA SIZE# %BufPtr %ENDIF mem? %ELSE sized? ; BufSize is explicitly specified. %PutArgSize %SET %BufSize %ENDIF sized? PUSHD %Frame, %PutArgSize, %BufPtr, %ArgNumber CALL PutArgLin32@RT:: PutArgLin32@RT::PROC1 PUSHAD MOV EBP,ESP MOV EDI,[%Param2] ; BufPtr. GetArg [%Param1],Frame=[%Param4] ; ArgNumber, Frame. JC .50: INC ECX CMP [%Param3],ECX ; BufSize. DEC ECX JNC .50: MOV ECX,[%Param3] ; BufSize. .50: MOV [%ReturnECX],ECX REP MOVSB JC .90: MOV [EDI],CL .90: POPAD RET 4*4 ENDP1 PutArgLin32@RT:: %ENDMACRO PutArg
SIZE# %BufPtr
will be used instead.
argc
value. It can be GPR or [DWORD_memory_variable].
Frame=ESP
is valid only if nothing has been pushed yet
since the program started. Otherwise use something like
LEA ECX,[ESP+4]
or LEA ECX,[EBP+8]
and then Frame=ECX
.executable
with environment strings TEMP=/tmp
and PATH=/bin:/usr/bin
launched from console as
./executable --option argumentA argumentB
PATH=/bin:/usr/bin
.
├────────┤
│ env1 │ Pointer to 1st ASCIIZ environment string TEMP=/tmp
.
├────────┤
│ 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-> └────────┘
PutEnv %MACRO EnvName$, BufPtr, BufSize, IgnoreCase=Yes, Frame=ESP sized? %IF %# = 2 mem? %IF %^PASS > 1 && TYPE#(SEGMENT# %BufPtr) != 'A' %ERROR ID=5814, 'Please specify the size of output buffer.' %EXITMACRO PutEnv %ELSE mem? ; BufPtr is specified as a memory variable with size. %PutEnvSize %SETA SIZE# %BufPtr %ENDIF mem? %ELSE sized? ; BufSize is explicitly specified. %PutEnvSize %SET %BufSize %ENDIF sized? %PutEnvCase %SETB %IgnoreCase PUSHD %Frame, %PutEnvCase, %PutEnvSize, %BufPtr, %EnvName$ CALL PutEnvLin32@RT:: PutEnvLin32@RT:: PROC1 PUSHAD MOV EBP,ESP XOR EAX,EAX MOV EDI,[%Param2] ; BufPtr. MOV [%ReturnECX],EAX ; Initialize returned ECX with 0. MOV [EDI],AL ; Initialize empty Buffer. MOV ESI,[%Param5] ; Frame. LODSD ; EAX=argc (1..127). CMP EAX,128 CMC JC .90: ; Abort with CF due to bad Frame. TEST EAX STC JZ .90: ; Abort with CF due to bad Frame. LEA ESI,[ESI+4*EAX] ; Pointers to argv* strings should be followed with NULL pointer. LODSD TEST EAX ; NUL pointer which terminates argv strings. STC JNZ .90: ; Abort with CF due to bad Frame. MOV EBX,ESI ; EBX points to array of pointers to ASCIIZ environment stringsNAME=value
. MOV EDI,[%Param1] ; EnvName$. MOV ESI,EDI XOR ECX,ECX NOT ECX REPNE SCASB NOT ECX MOV EDX,ECX ; ECX=EDX is now the size of EnvName$ string in bytes, including NUL. LEA EDI,[ECX+3] AND EDI,-4 ; Round RDI up to DWORD. SUB ESP,EDI ; Make room for lowercase EnvName$. MOV EDI,ESP .20: LODSB CMP AL,'A' JB .30: CMP AL,'Z' JA .30: OR AL,'x'^'X' ; Convert ASCII character to lowercase. .30: STOSB DEC ECX JNZ .20: .40: MOV ESI,EBX LODSD ; Pointer to env stringName=Value
. MOV EBX,ESI TEST EAX ; NUL pointer terminates env strings. JZ .90: ; Abort with CF=0, EnvName$ not found. MOV ESI,EAX XOR ECX,ECX MOV AL,'=' NOT ECX MOV EDI,ESI REPNE SCASB JNE .40: NOT ECX CMP ECX,EDX JNE .40: DEC ECX ; Netto size of EnvName$. TESTB [%Param4],1 ; IgnoreCase? JNZ .50: MOV EDI,[%Param1] ; EnvName$ - case sensitive search. REP CMPSB JNE .40: JMP .70: .50: MOV EDI,ESP ; Case insensitive search. .55: LODSB CMP AL,'A' JB .60: CMP AL,'Z' JA .60: OR AL,'x'^'X' ; Convert character to lowercase. .60: CMP AL,[EDI] JNE .40: INC EDI DEC ECX JNZ .55: .70: INC ESI ; Skip '=', point to EnvVal. MOV EDI,ESI XOR EAX,EAX NOT ECX REPNE SCASB SUB EDI,ESI ; EDI= required-by-value brutto size of EnvVal in bytes. MOV ECX,[%Param3] ; BufSize. EnvVal allocated-by-user brutto size in bytes. STC JECXZ .90: CMP ECX,EDI ; CF=overflow of EnvVal. XCHG ECX,EDI JAE .80: XCHG EDI,ECX .80: MOV EDI,[%Param2] ; BufPtr. MOV [%ReturnECX],ECX ; Returned ECX. REP MOVSB .90: MOV ESP,EBP POPAD RET 5*4 ENDP1 PutEnvLin32@RT:: %ENDMACRO PutEnv
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.
LF
(0x10) will be written on output after all strings have been written.
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
Macro StdInput reads from standard input specified by the Handle.
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 ENDP1 StdInputLin32@RT:: %ENDMACRO StdInput
Errorlevel=
, this value may also be specified as an ordinal operand.
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