EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

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

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
↑ %StdCall32
This assignments define preprocessing %variables useful to refer stack frame in 32bit StdCall calling convention.
See also
stdcal32.htm
 %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
↑ %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.
The most reliable source of system call numbers seems the header file /usr/include/asm/unistd.h or /usr/include/asm/unistd_32.h.
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
 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.
Examples
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). Special value 0 specifies the executable file itself. Special value -1 is used by GetArgCount to count arguments on cmd-line into ECX.
This parameter can be an immediate number below 128, 32bit GPR or memory variable.
Frame=ESP specifies the pointer to process stack, i.e. to the DWORD with process' argc value. It can be GPR or [DWORD_memory_variable].
The default 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.
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, PutArg
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
     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
↑ 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. It can be GPR or [DWORD_memory_variable].
The default 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.
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
↑ PutArg   ArgNumber, BufPtr, BufSize, Frame=ESP

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.

Input
ArgNumber is ordinal number of the required parameter. The 0-th parameter specifies the executable file itself. ArgNumber can be an immediate number below 128, 32bit GPR or memory variable.
BufPtr is pointer to the Buffer, i.e. to caller-reserved memory for the argument value.
BufSize is size of the reserved memory in bytes. This 3rd parameter may be omitted, SIZE# %BufPtr will be used instead.
Frame=ESP specifies the pointer to process stack, i.e. to the DWORD with process' argc value. It can be GPR or [DWORD_memory_variable].
The default 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.
Output
CF=0 if the requested value was successfully copied to Buffer and zero-terminated.
ECX=number of bytes written to Buffer, without the terminating NUL character.
ECX=0 when the ArgNumber-th argument does not exist and only NUL was written to Buffer.
Error
CF=1 bad Frame or the argument size overflowed BufSize and is therefore incomplete and not zero-terminated.
ECX=number of bytes written to the Buffer (never exceeds BufSize).
Tested by
tlinapi.htm
Depends on
GetArg
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
↑ PutEnv   EnvName$, BufPtr, BufSize, IgnoreCase=Yes, Frame=ESP
Macro PutEnv retrieves environment-variable with zero-terminated name EnvName$ at run-time, and copies its content to the memory specified by BufPtr, BufSize, including the NUL character at its end.
Input
EnvName$ is pointer to zero-terminated string with environment-variable name.
BufPtr is pointer to the caller-reserved memory for the variable value.
BufSize is size of the reserved memory in bytes. This 3rd parameter may be omitted, SIZE# %BufPtr will be used instead.
IgnoreCase=Yes is extended Boolean value specifying if PutEnv should search for EnvName$ case-insensitively.
Frame=ESP specifies the pointer to process stack, i.e. to the DWORD with process' argc value. It can be GPR or [DWORD_memory_variable].
The default 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.
Output
CF=0 if the requested value was successfully copied to Buffer and zero-terminated.
ECX= number of bytes written to BufPtr, without the terminating NUL character.
ECX=0 when the environment variable is empty or does not exist.
Error
CF=1 bad Frame or the value size overflowed BufSize and is therefore incomplete.
ECX= number of bytes written to the Buffer (never above BufSize).
Tested by
tlinapi.htm
Example
PutEnv =B"HOSTNAME", HostName JC .HostNameTooLong: JECXZ .HostNameNotSet: [.bss] HostName DB 64*BYTE
Process' stack layout of a program executable with environment strings TEMP=/tmp and PATH=/bin:/usr/bin launched from console as ./executable --option argumentA argumentB
┌────────┐ │ 0 │ NULL QWORD which terminates array of pointers to env strings. ├────────┤ │ env2 │ Pointer to 2nd ASCIIZ environment string 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 strings NAME=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 string Name=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
↑ 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
   ENDP1 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▲