| Index | Manual | Download | Source | Macros | Embedded word Case ins.
Sitemap | Links | Forum | Tests | Projects

# linapi.htm
Enumerations
%LinSyscall32List
%StdCall32
Macros
GetArg
GetArgCount
LinAPI
MemAlloc
MemFree
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(0),read(3),write(3),                        \ 000..004
     open(3),close(1),waitpid(3),creat(2),link(2),                               \ 005..009
     unlink(1),execve(3),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

↑ MemAlloc Size
  Macro MemAlloc allocates memory from Linux.
Input
  Size is the number of bytes allocated memory. It will be rounded up to the multiply of pagesize (4 KiB).
Output
  CF=0,
  EAX is pointer to the first byte of the allocated memory.
Error
  CF=1
  EAX=Error number
See also
  MemFree

    MemAlloc %MACRO Size
         PUSHD EBX,0,-1,MAP_PRIVATE|MAP_32BITS|MAP_ANONYMOUS,PROT_EXEC|PROT_READ|PROT_WRITE,%Size,0
           MOV EBX,ESP
           MOV EAX,90
           INT 0x80
           ADD ESP,6*4
         POP EBX
         CMP EAX,-ERR_MAX
         CMC
        %ENDMACRO MemAlloc

↑ MemFree Address, Size
  Macro MemFree unallocates memory from Linux.
Input
  Address as returned from MemAlloc which allocated it.
  Size is the size in bytes of the unallocated memory.
Output
  CF=0,
  EAX=0
Error
  CF=1
  EAX=Error number
See also
  MemAlloc

    MemFree %MACRO Address, Size=64K
         PUSH EBX,ECX
           MOV EAX,91
           MOV EBX,%Address
           MOV ECX,%Size
           INT 0x80
         POP ECX,EBX
         CMP EAX,-ERR_MAX
         CMC
        %ENDMACRO MemFree

↑ 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 ECX,EBX
         JC  .90:          ; This many arguments are not available, return with CF=1, 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:
  - STDOUT_FILENO = 1
  - STDERR_FILENO = 2
  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.
  Unicode=disabled, Console=disabled are ignored, they provide compatibility with Windows version.
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, Unicode=disabled, Console=disabled
    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+12*4]    ; File descriptor %Handle.
           MOV ECX,[ESP+11*4]    ; String maximal %Size.
           MOV EDI,[ESP+10*4]    ; 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:
  - STDIN_FILENO = 0
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▲