EuroAssembler Index Manual Download Source Macros


Sitemap Links Forum Tests Projects

cpuext64.htm
Macros
Align2Qword
Clear
Compare
CopyTo
LodD
LodH
StoD
StoH
StripApostrophes
StripColons
StripQuotes
StripSpaces

This file can be included to 64bit programs written in Euro Assembler.
The library contains OS-independent macroinstructions with calling convention similar to the standard Intel machine instruction set. They mostly pass operands in general-purpose registers and change the register contents on return.

Align* performs alignment at run time,
Clear, Compare, CopyTo provide some string operations,
Lod* converts numbers from human-readable notation to a binary number,
Sto* does the opposite,
Strip* trims the string from garbage characters which may surround it.

Similar macros with identical names for different program width are defined in cpuext16.htm and cpuext32.htm.

See also cpuext.htm for width-indepentent macros.


cpuext64 HEAD
; Definition of flags used by macros in this library.
%cpuextMinus    %SETA 0x80
%cpuextSigned   %SETA 0x40
%cpuextAlignL   %SETA 0x20
%cpuextLeading0 %SETA 0x10
%cpuextLowCase  %SETA 0x08
↑ Align2Qword
This inline macro will align the 64bit GPR or contents of memory variable to QWORD value upward.
Input
Variable is 32bit register or memory operand.
Output
CF=0, other registers unchanged.
Examples
Align2Qword RCX Align2Qword [QwPointer]
Align2Qword %MACRO Variable
               ADDQ %Variable,  7
               ANDQ %Variable, ~7
            %ENDMACRO Align2Qword
↑ Clear Operand, Size=, Filler=0
This macro will fill the string in memory at Operand offset with the character Filler=.
Input
Operand is pointer to a memory variable.
Size= specifies number of bytes to fill. By default it is SIZE# Operand.
Filler=0 is QWORD value whose LSB will be used to fill the Operand.
Output
All registers are preserved.
Examples
Clear Buffer1, Filler=" " ; Fill the whole memory variable Buffer1 with spaces. Clear RDI, Size=80, Filler=RAX ; Fill the memory at RDI with the contents of AL.
Clear %MACRO Operand, Size=, Filler=0
        PUSHQ %Operand
        %IF "%Size" !=== ""
          PUSHQ %Size
        %ELSE
          PUSHQ SIZE#(%Operand)
        %ENDIF
        PUSHQ %Filler
        CALL Clear@RT::
Clear@RT:: PROC1
    PUSH RAX,RCX,RDX,RDI
      MOV RDX,[RSP+40] ; %Filler.
      MOV ECX,8
.00:  SHRD RAX,RDX,8
      DEC ECX
      JNZ .00: ; Broadcast DL to all bytes or RAX.
      MOV RCX,[RSP+48] ; %Size.
      MOV RDI,[RSP+56] ; %Operand.
      SHR ECX,1
      JNC .10
      STOSB
.10:  SHR ECX,1
      JNC .20
      STOSW
.20:  SHR ECX,1
      JNC .30:
      STOSD
.30:  JRCXZ .90
      REP:STOSQ
.90:POP RDI,RDX,RCX,RAX
    RET 3*8
   ENDP1 Clear@RT::
%ENDMACRO Clear
↑ Compare Data1Ptr, Data1Size, Data2Ptr, Data2Size
This macro will compare two data fields (strings) byte per byte.
Input
Data1Ptr and Data1Size specify the first data field,
Data2Ptr andData2Size the second one.
The last parameter (Data2Size) may be omitted and it equals to Data1Size in this case.
Output
ZF=1 if both fields are identical, otherwise ZF=0. All registers are preserved, .
Examples
Compare F1, SIZE# F1, F2, SIZE# F2 Compare RDI,RSI,RCX
Compare  %MACRO Data1Ptr,Data1Size,Data2Ptr,Data2Size
         %IF %# < 3                                                                                ; >
           %ERROR ID=5911, "Macro Compare requires 3 or 4 parameters."
           %EXITMACRO Compare
         %ENDIF
         %IF %# > 3
           PUSHQ %Data2Size,%Data2Ptr,%Data1Size,%Data1Ptr
         %ELSE
           PUSHQ %Data1Size,%Data2Ptr,%Data1Size,%Data1Ptr
         %ENDIF
         CALL Compare@RT::
Compare@RT:: PROC1
       PUSH RCX,RSI,RDI
        MOV RSI,[RSP+32] ; %Data1Ptr
        MOV RCX,[RSP+40] ; %Data1Size
        MOV RDI,[RSP+48] ; %Data2Ptr
        CMP RCX,[RSP+56] ; %Data2Size
        JNE .90:
        REPE:CMPSB
   .90:POP RDI,RSI,RCX
       RET 4*8
  ENDP1 Compare@RT::
%ENDMACRO Compare
↑ CopyTo Destination, Source, Size=
This macro will copy the memory content from Source to Destination.
Input
Destination is a pointer to target memory.
Source is a pointer to the source of data.
Size= specifies number of bytes to copy. By default it is the SIZE# Destination attribute, if possible. The size may be alternatively specified with the keyword Size=.
Output
All registers are preserved.
Examples
CopyTo Buffer1, Buffer2 CopyTo RDI,RSI,RCX CopyTo RDI,Line,Size=80
CopyTo  %MACRO Destination, Source, Size=
        %IF "%Size" !=== ""
          PUSHQ %Size
        %ELSE
          %IF TYPE# %Destination = 'R'
            %ERROR ID=5912, "CopyTo data size not specified."
            %EXITMACRO CopyTo
          %ELSE
            PUSHQ SIZE# (%Destination)
          %ENDIF
         %ENDIF
      PUSHQ %Source, %Destination
      CALL CopyTo@RT::
CopyTo@RT:: PROC1
       PUSH RCX,RSI,RDI
        MOV RCX,[RSP+48] ; %Size
        MOV RSI,[RSP+40] ; %Source
        MOV RDI,[RSP+32] ; %Destination
        SHR ECX,1
        JNC .10:
        MOVSB
   .10: SHR ECX,1
        JNC .20:
        MOVSW
   .20: SHR ECX,1
        JNC .30:
        MOVSD
   .30: JRCXZ .90
        REP:MOVSD
   .90:POP RDI,RSI,RCX
       RET 3*8
  ENDPROC1 CopyTo@RT::
%ENDMACRO CopyTo
↑ LodD Source, Size=
Load signed or unsigned integer number in decimal notation and return its binary value in RAX.
LodD tolerates leading white spaces before the number and underscores _ inside the notation. The number may begin with + or -, at least one digit must immediately follow the sign.
Parsing stops when non-digit character is encountered or when the number of characters specified with Size= has been examinated.
Input
Source is a pointer to ANSI-encoded decimal number.
When the Source operand is not specified explicitly, RSI is assumed.
Size= specifies length of the source field in characters (=bytes). By default it is unlimited.
Output
CF=0, RAX=loaded number in the range -9_223_372_036_854_775_808 .. 18_446_744_073_709_551_615.
RSI points behind the last parsed digit.
Error
CF=1, RAX,RSI undefined
when the source number has wrong format:
1. After skipping the leading white spaces Source does not start with a digit or sign.
2. No digit immediately follows the sign.
3. Loaded number does not fit into 64 bits.
Example
InputField DB " -123.45" LodD InputField ; Loads RAX with -123d=0xFFFFFFFF_FFFFFF85
LodD  %MACRO  Source, Size=
    %IF "%Source" !== "" ; Explicit Source was specified.
      %LodDSource %SET %Source
    %ELSE
      %LodDSource %SET RSI
    %ENDIF
    %IF "%Size" !== "" ; Explicit Size was specified.
      PUSHQ %Size,%LodDSource
    %ELSE
      PUSHQ -1,%LodDSource
    %ENDIF
    CALL LodD@RT::
LodD@RT:: PROC1
     PUSH RCX,RDX,RBX,RDI
       MOV RDX,[RSP+48] ; Size.
       MOV RSI,[RSP+40] ; Source.
       MOV RCX,RDX
       ADD RDX,RSI ; Parse end limit.
       INC RCX
       JNZ .00:
       MOV RDX,-1
 .00:  SUB EAX,EAX
       SUB ECX,ECX ; Signum.
       SUB EBX,EBX ; Output value accumulator.
       MOV EDI,10
 .10:  CMP RSI,RDX
       JNB .Error:
       LODSB
       CMP AL,' '
       JBE .10: ; Skip leading white spaces.
       ; Sign or digit expected.
       CMP AL,'+'
       JE .20:
       CMP AL,'-'
       JNE .30:
       DEC RCX ; RCX is Minus flag.
 .20: ; At least one digit expected behind the signum, otherwise error.
       CMP RSI,RDX
       JNB .Error:
       LODSB
 .30:  SUB AL,'0'
       JB .Error:
       CMP AL,9
       JA .Error:
       MOV EBX,EAX ; Most significant digit loaded.
 .40: ; Other digits or underscores are expected, otherwise the parsing stops.
       CMP RSI,RDX
       JNB .EndOfNumber:
       LODSB
       CMP AL,'_'
       JE .40:
       SUB AL,'0'
       JB .EndOfNumber1:
       CMP AL,9
       JA .EndOfNumber1:
       XCHG RAX,RBX
       PUSH RDX
        MUL RDI
       POP RDX
       JC .Error:
       ADD RBX,RAX
       JC .Error:
       SUB EAX,EAX
       JMP .40:
 .Error:DEC RSI
       STC
       JMP .95:
 .EndOfNumber1:DEC RSI
 .EndOfNumber:
       TEST ECX ; Minus?
       JZ .90:
       NEG RBX
  .90: CLC
       MOV RAX,RBX
  .95:POP RDI,RBX,RDX,RCX
     RET 2*8
  ENDPROC1 LodD@RT::
%ENDMACRO LodD
↑ LodH Source, Size=, Align=left
Load 64bit number in hexadecimal notation to register RAX. Number may contain hexadecimal digits '0'..'9', 'a'..'f', 'A'..'F' optionally prefixed with '+' or '-' sign. LodH tolerates underscore '_' among digits. At least one hexadecimal digit should immediately follow the sign. Parsing stops when other non-hexadigit character is encountered or when Size= is exhausted.
Prefix 0x is not supported (LodH would return RAX=0 and RSI behind the 0x.
Input
Source is a pointer to the ANSI-encoded hexadecimal number.
RSI is assumed when the Source operand is not specified explicitly.
Size= is number of characters in the source field. When the size is not explicitly specified, SIZE# %Source is assumed. Size is not limited if it cannot be determined from %Source.
Align=left. By default the source must start with sign or hexadecimal digit. LodH tolerates leading white spaces only when Align=right.
Output
CF=0, RAX=loaded number
RSI= pointer behind the last parsed source digit.
Error
CF=1, RAX,RSI undefined
when the source number has wrong format:
1. source does not start with a hexadecimal digit or sign,
2. no hexadecimal digit immediately follows the sign,
3. loaded number does not fit into 64 bits.
Example
InputField DB "3FCh" LodH InputField ; loads RAX with 0x3FC=1020, RSI points to 'h'
LodH  %MACRO  Source, Size=, Align=left
    %LodHflags %SETA  %cpuextAlignL & "%Align[1]"=="L"
    %IF "%Source" === ""
      %LodHSource %SET RSI
    %ELSE
      %LodHSource %SET %Source
    %ENDIF
    %IF "%Size" !=== "" ; explicit Size was specified
      %LodHSize %SETA %Size
    %ELSE
      %LodHSize %SETA -1
      %IF "%LodHSource" !== "RSI"
         %LodHSize %SETA SIZE# (%LodHSource)
      %ENDIF
    %ENDIF
      PUSHD %LodHflags, %LodHSize, %LodHSource
    CALL LodH@RT::
LodH@RT:: PROC1
     PUSH RCX,RDX,RBX
       MOV RDX,[RSP+48] ; %LodHflags.
       MOV RCX,[RSP+40] ; %LodHSize.
       MOV RSI,[RSP+32] ; %LodHSource.
       SUB EAX,EAX
       SUB EBX,EBX      ; RBX will accumulate the binary value.
       JRCXZ .20:
       TEST DL,%cpuextAlignL
       JNZ .30:
  .10: LODSB ; White spaces are tolerated when Align=right.
       CMP AL,' '
       JA .40:
       DEC ECX
       JNZ  .10:
  .20: STC ; Error.
       JMP .95:
  .30: LODSB ; Signum or digit expected.
  .40: CMP AL,'+'
       JE .70:
       CMP AL,'-'
       JNE .60:
       OR DL, %cpuextMinus
       JMP .70:
  .50: LODSB ; Digit expected.
  .60: CMP AL,'_'
       JE .70:
       SUB AL,'0'
       JB .80:
       CMP AL,9
       JNA .65:
       SUB AL,'A'-'0'-10
       JB .80:
       CMP AL,15
       JNA .65
       SUB AL,'a'-'A'
       JB .80:
       CMP AL,15
       JA .80:
  .65: SAL RBX,4
       ADD RBX,RAX
       OR DL, %cpuextLeading0 ; At least one digit was found.
  .70: DEC ECX
       JNZ .50:
  .80: TEST DL, %cpuextLeading0
       JZ .20: ; Error if no digit was parsed.
       TEST DL, %cpuextMinus
       JZ .90:
       NEG RBX
  .90: CLC
       MOV RAX,RBX
 .95:POP RBX,RDX,RCX
     RET 3*8
  ENDP1 LodH@RT::
%ENDMACRO LodH
↑ StoD Destination, Size=, Signed=yes, Align=left, LeadingZeroes=no
Store 64bit integer in decimal notation.
Input
RAX contains the input number.
Destination is a pointer to memory where the decimal number will be stored. RDI is assumed when Destination is omitted.
Size= specifies length of the Destination field. When the size is not explicitly specified, it is taken from SIZE# %Destination . Size is not limited if it cannot be determined from %Destination. Size will never exceed 20 characters. The output string is ANSI (1byte per digit).
Signed=yes specifies whether the input number is treated as signed. Negative numbers will be prefixed with minus sign -, positive sign is not used.
Align=left specifies alignment (justification) of the number in Destination field. If Size= cannot be determined, this parameter is ignored. When Align=right and Size= is specified, the vacant characters on the left side will be filled with spaces or unsignificant leading zeroes.
LeadingZeroes=no specifies if the whole field should be filled with unsignificant 0 from the left side. Otherwise spaces would be used.
When Align=left or when the Size= is not specified, leading zeroes|spaces are not used.
Output
CF=0,
RDI points behind the last stored digit.
Error
CF=1 if Size= is not long enough,
EDI points to Destination, nothing is stored.
Example
OutputField DB 20 * B '?' MOV EAX,123 StoD OutputField MOV AL,'.' STOSB MOV EAX,45 StoD ; OutputField is now "123.45??????????????", ; RDI points to the 1st question mark
Layout
MOV RAX, 12345 MOV RAX, -12345 StoD Size=8 StoD Size=8 ┌─┬─┬─┬─┬─┬─┬─┬─┐ ┌─┬─┬─┬─┬─┬─┬─┬─┐ │1│2│3│4│5│ │ │ │ │-│1│2│3│4│5│ │ │ └─┴─┴─┴─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┴─┴─┴─┘ ^ ^ RDI RDI MOV RAX, 12345 MOV RAX, -12345 StoD Size=8, Align=right StoD Size=8, Align=right ┌─┬─┬─┬─┬─┬─┬─┬─┐ ┌─┬─┬─┬─┬─┬─┬─┬─┐ │ │ │ │1│2│3│4│5│ │ │ │-│1│2│3│4│5│ └─┴─┴─┴─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┴─┴─┴─┘ ^ ^ RDI RDI MOV RAX, 12345 MOV RAX, -12345 StoD Size=8, Align=right,\ StoD Size=8, Align=right,\ LeadingZeroes=yes LeadingZeroes=yes ┌─┬─┬─┬─┬─┬─┬─┬─┐ ┌─┬─┬─┬─┬─┬─┬─┬─┐ │0│0│0│1│2│3│4│5│ │-│0│0│1│2│3│4│5│ └─┴─┴─┴─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┴─┴─┴─┘ ^ ^ RDI RDI
StoD  %MACRO  Destination, Size=, Signed=yes, Align=left, LeadingZeroes=no
    %StoDflags %SETA              %cpuextSigned   & "%Signed[1]"!=="N"
    %StoDflags %SETA %StoDflags | %cpuextAlignL   & "%Align[1]"=="L"
    %StoDflags %SETA %StoDflags | %cpuextLeading0 & "%LeadingZeroes[1]"!=="N"
    %IF "%Destination"===""
       %StoDDestination %SET RDI ; Default destination if omitted.
    %ELSE
      %StoDDestination %SET %Destination
    %ENDIF
    %IF "%Size"!===""
      %StoDSize %SET %Size
    %ELSE
      %StoDSize %SETA -1 ; Default size is unlimited if destination/size not specified.
      %IF "%StoDDestination" !== "RDI"
        %StoDSize %SETA SIZE# (%Destination)
      %ENDIF
    %ENDIF
    %IF %StoDSize = -1 && "%Align[1]" !== "L"
      %ERROR ID=5913, "StoD cannot Align=right when Size is not specified."
      %StoDflags %SETA %StoDflags | %cpuextAlignL
    %ENDIF
    PUSHQ %StoDflags, %StoDSize, %StoDDestination
    CALL StoD@RT::
StoD@RT:: PROC1
    PUSH RAX,RCX,RDX,RBX,RBP,RSI
      SUB RSP,20+4       ; Room for temporary destination.
      MOV RDI,RSP
      MOV RCX,[RSP+96]   ; %StoDflags.
      MOV RBX,RAX        ; The input integer number is now in RBX.
      TEST CL,%cpuextSigned
      JZ .10:
      TEST RBX
      JNS .10:
      NEG RBX            ; Convert RBX to positive number.
      OR CL,%cpuextMinus ; Result will be prefixed with '-'.
.10:
divsr %FOR 10000000000000000000, \ 1019.
            1000000000000000000, \ 1018.
             100000000000000000, \ 1017.
              10000000000000000, \ 1016.
               1000000000000000, \ 1015.
                100000000000000, \ 1014.
                 10000000000000, \ 1013.
                  1000000000000, \ 1012.
                   100000000000, \ 1011.
                    10000000000, \ 1010.
                     1000000000, \ 109.
                      100000000, \ 108.
                       10000000, \ 107.
                        1000000, \ 106.
                         100000, \ 105.
                          10000, \ 104.
                           1000, \ 103.
                            100, \ 102.
                             10  ; 101.
        MOV RBP,%divsr
        CALL .Divide:
 .Divide:PROC1           ; Divide divident RBX by divisor RBP.
          SUB EDX,EDX
          XCHG RBX,RAX   ; Zero extend divident RBX to RDX:RAX.
          DIV RBP        ; RAX is now 0..9.
          ADD AL,'0'     ; Convert to decimal digit.
          STOSB          ; Store to temporary destination.
          XCHG RDX,RBX   ; Copy remainder to RBX.
          RET
         ENDP1 .Divide:
      %ENDFOR divsr      ; Repeat with smaller divisor.
      MOV AL,BL          ; The last remainder.
      ADD AL,'0'         ; Convert to decimal digit.
      STOSB              ; String of 20 digits at RSP now contains the temporary result.
      MOV RSI,RSP        ; Pointer to temporary result with leading decimal zeros.
      LEA RBX,[RSP+20-1] ; Pointer to the last digit in temporary result.
.20:  CMP RSI,RBX
      JNB .30:           ; If no more zeros to skip.
      LODSB
      CMP AL,'0'
      JE .20:            ; Skip leading unsignificant zeros.
      DEC RSI
.30:  INC RBX
      SUB RBX,RSI        ; Unsigned result without leading zeros is now in RSI,RBX.
      MOV RDX,[RSP+88]   ; %StoDSize.
      MOV RDI,[RSP+80]   ; %StoDDestination.
      TEST RDX
      STC
      JZ .Overflow:
      TEST CL,%cpuextMinus
      JZ .40:
      DEC RDX
.40:  SUB RDX,RBX        ; RDX is now the number of padding bytes in destination.
      JC .Overflow:
      TEST CL,%cpuextAlignL
      JZ .50:
      TEST CL,%cpuextMinus
      JZ .90:
      MOV AL,'-'
      STOSB
      JMP .90:
.50:  ; Justify the result to the right.
      TEST CL,%cpuextMinus
      JZ .70:
      TEST CL,%cpuextLeading0
      MOV ECX,EDX
      JZ .60:
      MOV AL,'-'
      STOSB
      MOV AL,'0'
      REP:STOSB
      JMP .90:
.60:  MOV AL,' '
      REP STOSB
      MOV AL,'-'
      STOSB
      JMP .90:
.70:  TEST CL,%cpuextLeading0
      MOV AL,' '
      JZ .80:
      MOV AL,'0'
.80:  MOV ECX,EDX
      REP:STOSB
.90:  MOV ECX,EBX
      REP:MOVSB
.Overflow:  ; CF signalizes error.
      LEA RSP,[RSP+20+4]
    POP RSI,RBP,RBX,RDX,RCX,RAX
    RET 3*8
  ENDP1 StoD@RT::
%ENDMACRO StoD
↑ StoH Destination, Size=, Case=upper, Align=right, LeadingZeroes=yes
Store 64bit integer number converted to hexadecimal notation (without radix modifier 0x and H. The number is always treated as signed. When it is negative, its converted first significant digit has the MSbit=1 (8..F). First significant digit of positive number is 1..7.
Input
RAX contains the input number.
Destination is a pointer to memory where the number in hexadecimal notation will be stored. RDI is assumed when Destination is omitted.
Size= specifies the number of bytes in the Destination field. When the size is not explicitly specified, it is taken from SIZE# %Destination. Size is not limited if it cannot be determined from %Destination but it will never exceed 16 bytes. The output string is ANSI (1byte per digit).
Case=upper (or lower). This parameter will select between ABCDEF and abcdef digits.
Align=right (or left) specifies alignment (justification) of the number in Destination field. If Size= cannot be determined, this parameter is ignored and the result is left-justified. Only significant hexadecimal digits are stored (at least one).
When Align=right and Size= is specified, the vacant room on the left side will be filled with spaces or unsignificant leading characters 0 or F (this depends on the signum of input value).
LeadingZeroes=yes (or no) specifies if the whole field should be filled from the left side with unsignificant 0 or F. When Align=left or when the Size= is not determined, leading characters are not used and only significant nibbles are stored.
Output
CF=0,
RDI points behind the last stored destination digit.
Error
CF=1 if Size= is not long enough to store all significant digits without overflow,
RDI points to Destination, nothing is stored.
Layout
MOV RAX, 0x123 MOV RAX, -0x123 StoH Size=8 StoH Size=8 ┌─┬─┬─┬─┬─┬─┬─┬─┐ ┌─┬─┬─┬─┬─┬─┬─┬─┐ │0│0│0│0│0│1│2│3│ │F│F│F│F│F│E│D│D│ └─┴─┴─┴─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┴─┴─┴─┘ ^ ^ RDI RDI MOV RAX, 0x123 MOV RAX, -0x123 StoH Size=8, \ StoH Size=8, \ LeadingZeroes=no LeadingZeroes=no ┌─┬─┬─┬─┬─┬─┬─┬─┐ ┌─┬─┬─┬─┬─┬─┬─┬─┐ │ │ │ │ │ │1│2│3│ │ │ │ │ │ │E│D│D│ └─┴─┴─┴─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┴─┴─┴─┘ ^ ^ RDI RDI MOV RAX, 0x123 MOV RAX, -0x123 StoH Size=8, Align=left StoH Size=8, Align=left ┌─┬─┬─┬─┬─┬─┬─┬─┐ ┌─┬─┬─┬─┬─┬─┬─┬─┐ │1│2│3│ │ │ │ │ │ │E│D│D│ │ │ │ │ │ └─┴─┴─┴─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┴─┴─┴─┘ ^ ^ RDI RDI
StoH  %MACRO  Destination, Size=, Case=Upper, Align=Right, LeadingZeroes=Yes
    %StoHflags %SETA              %cpuextLowCase  & "%Case[1]"!=="U"
    %StoHflags %SETA %StoHflags | %cpuextAlignL   & "%Align[1]"!=="R"
    %StoHflags %SETA %StoHflags | %cpuextLeading0 & "%LeadingZeroes[1]"=="Y"
    %IF "%Destination"===""
      %StoHDestination %SET RDI ; Default destination if omitted.
    %ELSE
      %StoHDestination %SET %Destination
    %ENDIF
    %IF "%Size"!===""
      %StoHSize %SET %Size
    %ELSE
      %StoHSize %SETA -1 ; Default size is unlimited if destination/size not specified.
      %IF "%StoHDestination" !== "RDI"
        %StoHSize %SETA SIZE# (%Destination)
      %ENDIF
    %ENDIF
    %IF %StoHSize = -1 && "%Align[1]"!=="L"
      %ERROR ID=5915, "StoH cannot Align=right when Size= is not specified."
      %StoHflags %SETA %StoHflags | %cpuextAlignL
    %ENDIF
    PUSHQ %StoHflags, %StoHSize, %StoHDestination
    CALL StoH@RT::
StoH@RT:: PROC1
     PUSH RAX,RCX,RDX,RBX,RBP,RSI
       SUB RSP,16               ; Room for temporary destination.
       MOV RDI,RSP
       MOV RDX,[RSP+88]         ; %StoHflags.
       MOV RBX,RAX              ; Input value.
       MOV ECX,16               ; Number of 4bit nibbles in RBX.
       TEST DL,%cpuextLowCase
       JZ .10:
       OR DH,'x'^'X'            ; DH is 0x00 or 0x20 for upper or lower case.
.10:   ROL RBX,4                ; Start with the most significant nibble.
       MOV AL,0x0F
       AND AL,BL
       OR  AL,'0'
       CMP AL,'9'
       JBE .20:
       ADD AL,'A'-'0'-10        ; AL='A'..'F'.
       OR  AL,DH                ; Convert to lower case if DH=0x20.
.20:   STOSB
       DEC RCX
       JNZ .10:
       TEST RBX                 ; 16 bytes of temporary room at RSP is filled with hexadecimal digits.
       JNS .25:
       OR DH,'F'                ; Prepare DH=unsignificant digit 'F' or 'f'.
       JMP .30:
.25:   MOV DH,'0'               ; Prepare DH=unsignificant digit '0'.
       JNZ .30:
       INC BL                   ; If input number = 0, one significant digit '0' is stored.
       JMP .50:
.30:   BSR RCX,RBX              ; Find the most significat bit for both positive and negative value.
       NOT RBX
       BSR RBX,RBX
       CMP BL,CL
       JB .40:
       XCHG BL,CL               ; Select the minimum.
.40:   ADD BL,5
       SHR BL,2                 ; RBX is now the number of significant output nibbles (1..16).
.50:   LEA RSI,[RSP+16]         ; End of temporary room.
       MOV RCX,[RSP+80]         ; %StoHSize.
       MOV RDI,[RSP+72]         ; %StoHDestination.
       SUB RSI,RBX              ; RSI now points to 1st significant digit.
       TEST DL,%cpuextAlignL
       JNZ .70:
       SUB RCX,RBX
       JC .Overflow:
       MOV AL,DH
       TEST DL,%cpuextLeading0
       JNZ .60:
       MOV AL,' '
.60:   REP:STOSB                ; Store RCX spaces or unsignificant digits.
.70:   MOV RCX,RBX
       REP:MOVSB                ; Store RBX significant digits.
.Overflow:                      ; CF signalizes error.
       LEA RSP,[RSP+16]
     POP RSI,RBP,RBX,RDX,RCX,RAX
     RET 3*8
  ENDP1 StoH@RT::
 %ENDMACRO StoH
↑ StripColons PtrReg, SizeReg, Unicode=%^UNICODE
Remove leading and trailing colon(s) : from input field.
Input
PtrReg is a register which points to the input field.
SizeReg is a register with size of the input field in bytes. Both arguments must be specified as general purpose 64bit registers.
Unicode= is a logical parameter which tells whether the strings is ANSI or WIDE.
Output
Both input registers are changed if the field begins and|or ends with colons. If the input field only contains one or more colons, the 2nd register will return 0.
StripColons %MACRO PtrReg, SizeReg, Unicode=%^UNICODE
      %IF TYPE#%PtrReg <> 'R' || TYPE#%SizeReg <> 'R'
        %ERROR ID=5918, "Both arguments of StripColons must be GPR."
        %EXITMACRO StripColons
      %ENDIF
      %IF %Unicode ; WIDE variant.
 StripColons1%.:
        CMP %SizeReg,2
        JL StripColons9%.:
        CMPW [%PtrReg+%SizeReg-2],":"
        JNE StripColons2%.:
        SUB %SizeReg,2
        JMP StripColons1%.:
 StripColons2%.:
        CMPW [%PtrReg],":"
        JNE StripColons9%.:
        ADD %PtrReg,2
        CMP %SizeReg,2
        JL StripColons9%.:
        SUB %SizeReg,2
        JMP StripColons2%.:
 StripColons9%.:
      %ELSE ; ANSI variant.
        TEST %SizeReg
        JZ StripColons9%.:
 StripColons1%.:
        CMPB [%PtrReg+%SizeReg-1],':'
        JNE StripColons2%.:
        DEC %SizeReg
        JNG StripColons9%.:
        JMP StripColons1%.:
 StripColons2%.:
        CMPB [%PtrReg],':'
        JNE StripColons9%.:
        INC %PtrReg
        DEC %SizeReg
        JMP StripColons2%.:
      %ENDIF
 StripColons9%.:
 %ENDMACRO StripColons
↑ StripQuotes PtrReg, SizeReg, Unicode=%^UNICODE
Remove leading and trailing double quote " from input field.
Input
PtrReg is a register which points to the input field.
SizeReg is the register with size of the input field in bytes. Both arguments must be specified as general purpose 64bit registers.
Unicode= is a logical parameter which tells whether the strings is ANSI or WIDE.
Output
Both input registers are changed if the field begins and/or ends with double quote. If the input field only contains two quotes, the 2nd register will return 0.
StripQuotes %MACRO PtrReg, SizeReg, Unicode=%^UNICODE
      %IF TYPE#%PtrReg <> 'R' || TYPE#%SizeReg <> 'R'
        %ERROR ID=5919, "Both arguments of StripQuotes must be GPR."
        %EXITMACRO StripQuotes
      %ENDIF
      %IF %Unicode  ; WIDE variant.
        CMP %SizeReg,2*2
        JB StripQuotes9%.:
        CMPW [%PtrReg+%SizeReg-2],'"'
        JNE StripQuotes1%.:
        SUB %SizeReg,2
 StripQuotes1%.:
        CMPW [%PtrReg],'"'
        JNE StripQuotes9%.:
        ADD %PtrReg,2
        SUB %SizeReg,2
 StripQuotes9%.:
      %ELSE  ; ANSI variant.
        CMP %SizeReg,2
        JB StripQuotes9%.:
        CMPB [%PtrReg+%SizeReg-1],'"'
        JNE StripQuotes1%.:
        DEC %SizeReg
 StripQuotes1%.:
        CMPB [%PtrReg],'"'
        JNE StripQuotes9%.:
        INC %PtrReg
        DEC %SizeReg
StripQuotes9%.:
     %ENDIF
 %ENDMACRO StripQuotes
↑ StripApostrophes PtrReg, SizeReg, Unicode=%^UNICODE
Remove leading and trailing single quote ' from input field.
Input
PtrReg is a register which points to the input field.
SizeReg is register with size of the input field in bytes. Both arguments must be specified as general purpose 64bit registers.
Unicode= is a logical parameter which tells whether the strings is ANSI or WIDE.
Output
Both input registers are changed if the field begins and/or ends with apostrophe. If the input field only contains two apostrophes, the 2nd register will return 0.
StripApostrophes %MACRO PtrReg, SizeReg, Unicode=%^UNICODE
      %IF TYPE#%PtrReg <> 'R' || TYPE#%SizeReg <> 'R'
        %ERROR ID=5917, "Both arguments of StripApostrophes must be GPR."
        %EXITMACRO StripApostrophes
      %ENDIF
      %IF %Unicode  ; WIDE variant.
        CMP %SizeReg,2*2
        JB StripApostrophes9%.:
        CMPW [%PtrReg+%SizeReg-2],"'"
        JNE StripApostrophes1%.:
        SUB %SizeReg,2
 StripApostrophes1%.:
        CMPW [%PtrReg],"'"
        JNE StripApostrophes9%.:
        ADD %PtrReg,2
        SUB %SizeReg,2
 StripApostrophes9%.:
      %ELSE  ; ANSI variant.
        CMP %SizeReg,2
        JB StripApostrophes9%.:
        CMPB [%PtrReg+%SizeReg-1],"'"
        JNE StripApostrophes1%.:
        DEC %SizeReg
 StripApostrophes1%.:
        CMPB [%PtrReg],"'"
        JNE StripApostrophes9%.:
        INC %PtrReg
        DEC %SizeReg
 StripApostrophes9%.:
      %ENDIF
 %ENDMACRO StripApostrophes
↑ StripSpaces PtrReg, SizeReg, Unicode=%^UNICODE
Remove white spaces (characters equal or below ASCII 32) which surround the input field.
Input
PtrReg is a register which points to the input field.
SizeReg is a register with size of the input field in bytes. Both arguments must be specified as general purpose 64bit registers.
Unicode= is a logical parameter which tells whether the strings is ANSI or WIDE.
Output
Both input registers are changed if the field begins and/or ends with white spaces. If the input field contains nothing but spaces, the 2nd register will return 0.
Example
Field: DB " some text ",13,10,0 MOV ESI,Field MOV ECX,SIZE# Field ; 14 StripSpaces ESI,ECX ; ESI=Field+1 ECX=9
StripSpaces %MACRO PtrReg, SizeReg, Unicode=%^UNICODE
      %IF TYPE#%PtrReg <> 'R' || TYPE#%SizeReg <> 'R'
        %ERROR ID=5920, "Both arguments of StripSpaces must be GPR."
        %EXITMACRO StripSpaces
      %ENDIF
      %IF %Unicode ; WIDE variant.
 StripSpaces1%.:
        CMP %SizeReg,2
        JL StripSpaces9%.:
        CMPW [%PtrReg+%SizeReg-2]," "
        JA StripSpaces2%.:
        SUB %SizeReg,2
        JMP StripSpaces1%.:
 StripSpaces2%.:
        CMPW [%PtrReg]," "
        JA StripSpaces9%.:
        ADD %PtrReg,2
        CMP %SizeReg,2
        JL StripSpaces9%.:
        SUB %SizeReg,2
        JMP StripSpaces2%.:
 StripSpaces9%.:
      %ELSE  ; ANSI variant.
        TEST %SizeReg
        JZ StripSpaces9%.:
 StripSpaces1%.:
        CMPB [%PtrReg+%SizeReg-1]," "
        JA StripSpaces2%.:
        DEC %SizeReg
        JNG StripSpaces9%.:
        JMP StripSpaces1%.:
 StripSpaces2%.:
        CMPB [%PtrReg]," "
        JA StripSpaces9%.:
        INC %PtrReg
        DEC %SizeReg
        JMP StripSpaces2%.:
 StripSpaces9%.:
      %ENDIF
 %ENDMACRO StripSpaces
 ENDHEAD cpuext64

▲Back to the top▲