Hi
Recently I rewrote some older code to remove a windows dependency, mainly printf. This gave me the idea to think about whether there couldn't be a better way to do the job of printf.
Since printf's format string doesn't change in most cases, it's possible to find another approach to get a more performant result.
The idea is to find a similar way, sort of like HSE did in its PrintC macro.
The macro should parse the format string and generate the code according to the result of the parser.
MASM is ideal for this task provided we have all the necessary subroutines to get the job done.
Biterider
Good idea :thumbsup:
What I find strange is that C/C++ are not able to choose the format automagically, as in
print MyReal8. In MASM, you can easily write a macro that checks whether the argument is an integer, a QWORD, a REAL8 etc - see attachment (pure Masm32 SDK) :cool:
Quote from: HSE on June 14, 2022, 07:21:36 AM
PrintC is in efiutil.inc (https://github.com/ASMHSE/ObjAsm-C.1uefi/blob/f5f39ebb55a1c1ebf92feeab7b7b9d52e51ff7c0/Code/Inc/UEFI/efiUtil.inc)
Quote from: jj2007 on June 21, 2022, 07:09:40 PM
What I find strange is that C/C++ are not able to choose the format automagically,
C++ have classes for that, C don't.
But some C compilers have extension
__typeof
Hi Biterider!
Quote from: Biterider on June 21, 2022, 04:19:24 PM
The idea is to find a similar way, sort of like HSE did in its PrintC macro.
:thumbsup: That macro is a very elemental FSM wich read a character code between "%" and space. To emulate C' prints FSM must be more complex and read several characters code between [% or \ ] and [%, \,space, "," , ";" or "."] (at least).
Regards, HSE.
Hi all!
Following Biterider challenge, this is a far better approach than in my previous macro:
PrintH1 macro mensaje, args:VARARG
local pos1
ifndef crlf1$
CStr crlf1$ , 13, 10, 0
endif
ifndef cr1$
CStr cr1$, 13, 0
endif
ifndef lf1$
CStr lf1$, 10, 0
endif
ifndef tab1$
CStr tab1$, 9, 0
endif
ifndef UEFI_Print_Message
UEFI_Print_Message = 0
else
UEFI_Print_Message = UEFI_Print_Message + 1
endif
ifndef UEFI_Print_buffer1
.data
UEFI_Print_buffer1 CHR 1024 dup (0)
UEFI_Print_buffer2 CHR 248 dup (0)
UEFI_Print_buffer3 CHR 4 dup (0)
CStr UEFI_Error_0, "EFI_SUCCESS"
CStr UEFI_Error_1, "EFI_LOAD_ERROR"
CStr UEFI_Error_2, "EFI_INVALID_PARAMETER"
CStr UEFI_Error_3, "EFI_UNSUPPORTED"
CStr UEFI_Error_4, "EFI_BAD_BUFFER_SIZE"
CStr UEFI_Error_5, "EFI_BUFFER_TOO_SMALL"
CStr UEFI_Error_6, "EFI_NOT_READY"
CStr UEFI_Error_7, "EFI_DEVICE_ERROR"
CStr UEFI_Error_8, "EFI_WRITE_PROTECTED"
CStr UEFI_Error_9, "EFI_OUT_OF_RESOURCES"
CStr UEFI_Error_10, "EFI_VOLUME_CORRUPTED"
CStr UEFI_Error_11, "EFI_VOLUME_FULL"
CStr UEFI_Error_12, "EFI_NO_MEDIA"
CStr UEFI_Error_13, "EFI_MEDIA_CHANGED"
CStr UEFI_Error_14, "EFI_NOT_FOUND"
CStr UEFI_Error_15, "EFI_ACCESS_DENIED"
CStr UEFI_Error_16, "EFI_NO_RESPONSE"
CStr UEFI_Error_17, "EFI_NO_MAPPING"
CStr UEFI_Error_18, "EFI_TIMEOUT"
CStr UEFI_Error_19, "EFI_NOT_STARTED"
CStr UEFI_Error_20, "EFI_ALREADY_STARTED"
CStr UEFI_Error_21, "EFI_ABORTED"
CStr UEFI_Error_22, "EFI_ICMP_ERROR"
CStr UEFI_Error_23, "EFI_TFTP_ERROR"
CStr UEFI_Error_24, "EFI_PROTOCOL_ERROR"
CStr UEFI_File_Error_0, "EFI_SUCCESS" ;"The file was opened."
CStr UEFI_File_Error_1, "EFI_NOT_FOUND" ;"The specified file could not be found on the device."
CStr UEFI_File_Error_2, "EFI_NO_MEDIA" ;"The device has no medium."
CStr UEFI_File_Error_3, "EFI_MEDIA_CHANGED" ;"The device has a different medium in it or the medium is no longer supported."
CStr UEFI_File_Error_4, "EFI_DEVICE_ERROR" ;"The device reported an error."
CStr UEFI_File_Error_5, "EFI_VOLUME_CORRUPTED" ;"The file system structures are corrupted."
CStr UEFI_File_Error_6, "EFI_WRITE_PROTECTED" ;"An attempt was made to create a file, or open a file for write when the media is write-protected."
CStr UEFI_File_Error_7, "EFI_ACCESS_DENIED" ;"The service denied access to the file."
CStr UEFI_File_Error_8, "EFI_OUT_OF_RESOURCES" ;"Not enough resources were available to open the file."
CStr UEFI_File_Error_9, "EFI_VOLUME_FULL" ;"The volume is full."
if 0
cuenta = 1
EFI_ERROR$ dq offset UEFI_Error_0
REPEAT 24
% dq offset @CatStr(<UEFI_Error_>,%cuenta)
cuenta = cuenta + 1
ENDM
cuenta = 1
EFI_FILE_ERROR$ dq offset UEFI_File_Error_0
REPEAT 9
% dq offset @CatStr(<UEFI_File_Error_>,%cuenta)
cuenta = cuenta + 1
ENDM
endif
endif
.code
freg_pushad
cuenta = 0
FOR arg,<args>
@CatStr(<argumento_>,%cuenta) textequ <arg>
cuenta = cuenta + 1
ENDM
mov rax, 0
mov CHR ptr UEFI_Print_buffer1, ax
cuenta = 0
pos1 = 0
parte = 0
contenido TEXTEQU <>
tipoarg TEXTEQU <>
abrecomilla = 0
hayslack = 0
haypercent = 0
abierto = 0
FORC char,<&mensaje>
tk_1 INSTR 1,<">,<&char>
if tk_1 EQ 0
if (abrecomilla eq 0) or (abrecomilla eq 2)
.err Problem with string delimitation
endif
tk_2a INSTR 1,<\>,<&char>
if tk_2a
if hayslack
hayslack = 0
contenido CATSTR contenido,<!!!\>
goto continue
else
hayslack = 1
goto continue
endif
endif
tk_2b INSTR 1,<%>,<&char>
if tk_2b
if hayslack
hayslack = 0
elseif haypercent
.err Not allowed percent sucesive symbols
else
haypercent = 1
goto continue
endif
endif
tk_3a INSTR 1, <rnt>, <&char>
if tk_3a
if hayslack
if abierto
abierto = 0
@CatStr(<CStrW UEFI_Print_Message_>,%UEFI_Print_Message,<_>,%parte,<, !">,%contenido,<!">)
invoke StrCat, addr UEFI_Print_buffer1, addr @CatStr(<UEFI_Print_Message_>,%UEFI_Print_Message,<_>,%parte)
contenido TEXTEQU <>
parte = parte + 1
endif
tk_3a1 INSTR 1, <r>, <&char>
if tk_3a1
invoke StrCat, addr UEFI_Print_buffer1, addr cr1$
endif
tk_3a2 INSTR 1, <n>, <&char>
if tk_3a2
invoke StrCat, addr UEFI_Print_buffer1, addr lf1$
endif
tk_3a3 INSTR 1, <t>, <&char>
if tk_3a3
invoke StrCat, addr UEFI_Print_buffer1, addr tab1$
endif
hayslack = 0
goto continue
endif
endif
tk_3b INSTR 1, <scdihfgrq>, <&char>
if tk_3b
if haypercent
if abierto
abierto = 0
@CatStr(<CStrW UEFI_Print_Message_>,%UEFI_Print_Message,<_>,%parte,<, !">,%contenido,<!">)
invoke StrCat, addr UEFI_Print_buffer1, addr @CatStr(<UEFI_Print_Message_>,%UEFI_Print_Message,<_>,%parte)
contenido TEXTEQU <>
parte = parte + 1
endif
tk_3b1 INSTR 1, <s>, <&char>
if tk_3b1
invoke StrCat, addr UEFI_Print_buffer1, @CatStr(<argumento_>,%cuenta)
endif
tk_3b1 INSTR 1, <c>, <&char>
if tk_3b1
mov ax, @CatStr(<argumento_>,%cuenta)
mov UEFI_Print_buffer3, ax
invoke StrCat, addr UEFI_Print_buffer1, addr UEFI_Print_buffer3
endif
tk_3b1 INSTR 1, <d>, <&char>
if tk_3b1
invoke uqword2decW, addr UEFI_Print_buffer2, @CatStr(<argumento_>,%cuenta)
invoke StrCat, addr UEFI_Print_buffer1, addr UEFI_Print_buffer2
endif
tk_3b1 INSTR 1, <i>, <&char>
if tk_3b1
invoke udword2decW, addr UEFI_Print_buffer2, @CatStr(<argumento_>,%cuenta)
invoke StrCat, addr UEFI_Print_buffer1, addr UEFI_Print_buffer2
endif
tk_3b1 INSTR 1, <h>, <&char>
if tk_3b1
invoke qword2hexW, addr UEFI_Print_buffer2, @CatStr(<argumento_>,%cuenta)
invoke StrCat, addr UEFI_Print_buffer1, addr UEFI_Print_buffer2
endif
tk_3b1 INSTR 1, <f>, <&char>
if tk_3b1
fld @CatStr(<argumento_>,%cuenta)
invoke St0ToStr, addr UEFI_Print_buffer2, 8, 4, 0
fstp st
invoke StrCat, addr UEFI_Print_buffer1, addr UEFI_Print_buffer2
endif
tk_3b1 INSTR 1, <g>, <&char>
if tk_3b1
freg_pushad
invoke GUID2StrW, addr UEFI_Print_buffer2, @CatStr(<argumento_>,%cuenta)
invoke StrCat, addr UEFI_Print_buffer1, addr UEFI_Print_buffer2
freg_popad
endif
tk_3b1 INSTR 1, <r>, <&char>
if tk_3b1
cuento = 1
%mov rax, @CatStr(<argumento_>,%cuenta)
and rax, 0FFh
.if rax == 0
lea rdx, @CatStr(<UEFI_Error_>, 0)
repeat 24
% .elseif rax == cuento
lea rdx, @CatStr(<UEFI_Error_>, %cuento)
cuento = cuento + 1
endm
.endif
invoke StrCat, addr UEFI_Print_buffer1, rdx
endif
tk_3b1 INSTR 1, <q>, <&char>
if tk_3b1
cuento = 1
%mov rax, @CatStr(<argumento_>,%cuenta)
and rax, 0FFh
.if rax == 0
%lea rdx, @CatStr(<UEFI_File_Error_>, 0)
repeat 9
% .elseif rax == cuento
%lea rdx, @CatStr(<UEFI_File_Error_>, %cuento)
cuento = cuento + 1
endm
.endif
invoke StrCat, addr UEFI_Print_buffer1, rdx
endif
cuenta = cuenta + 1
haypercent = 0
goto continue
endif
endif
abierto = 1
else
if abrecomilla EQ 1
if abierto
@CatStr(<CStrW UEFI_Print_Message_>,%UEFI_Print_Message,<_>,%parte,<, !">,%contenido,<!">)
invoke StrCat, addr UEFI_Print_buffer1, addr @CatStr(<UEFI_Print_Message_>,%UEFI_Print_Message,<_>,%parte)
contenido TEXTEQU <>
endif
abrecomilla = 2
abierto = 0
else
abrecomilla = 1
endif
endif
if abierto
contenido CATSTR contenido,<&char>
endif
:continue
ENDM
mov xcx, pConsoleOut
invoke [xcx].ConOut.OutputString, xcx, ADDR UEFI_Print_buffer1
freg_popad
endm
Escapes are:
\\ ="\"
\% = "%"
\r = begin of line
\n = new line
\t = tab
Variables:
%s = string by addr
%c = character
%h =hexagesimal
%i = decimal dword
%d = decimal qword
%f = floating point (real4 or real8)
%g = GUID value
%r = EFI error
%q = EFI file error
then:
PrintH " %i %i %i - %i:%i:%i.%i ", [xbx].EFI_TIME.Month, [xbx].EFI_TIME.Day, [xbx].EFI_TIME.Year, [xbx].EFI_TIME.Hour, [xbx].EFI_TIME.Minute, [xbx].EFI_TIME.Second, [xbx].EFI_TIME.Nanosecond ; GNU-EFI apparently has a print function for time... Oh well.
show: 7 30 2022 - 20:57:40.0
PrintH "SetAttribute \\\% %r \n\n", Status
show:SetAttribute \% EFI_SUCCESS
Obvioulsly, more tests are needed :biggrin:
Regards, HSE
Hi
I finally have some time to experiment a bit with this idea.
It wasn't as hard as I expected as most of the parts already existed.
The macro I call PrintF supports format specifiers used to interpret the passed varargs, as well as escape sequences to use non-printable characters or MASM special characters.
The documentation as well as the code can be found in the attached file.
ObjAsm users will find the macro in the System.inc file.
Example:
lea xdi, cBuffer
mov CHR ptr [xdi], 0
mov xsi, 12345678h
PrintF xdi, 'The content at memory location ¦HXh is ¦F3 ml ¦ST', xsi, $CReal4(1.23), $OfsCStr("(current reading)")
DbgStr cBuffer
lea xdi, cBuffer
PrintF xdi, "Memory at \[¦HXh\]: ¦EB", xsi, $CReal8(1.23456789123456789)
DbgStr cBuffer
Result:
cBuffer = The content at memory location 12345678h is 1.230 ml (current reading)
cBuffer = Memory at <12345678h>: 1.23456789123E+0000
The code generated runs much faster than a printf call because it is tailored by the macro for this specific case.
In this case, the code for ANSI characters in 64-bit looks like this:
lea rdi,[cBuffer]
mov byte ptr [rdi],0
mov rsi,12345678h
mov dword ptr [rdi],20656854h
mov dword ptr [rdi+4],746E6F63h
mov dword ptr [rdi+8],20746E65h
mov dword ptr [rdi+0Ch],6D207461h
mov dword ptr [rdi+10h],726F6D65h
mov dword ptr [rdi+14h],6F6C2079h
mov dword ptr [rdi+18h],69746163h
mov word ptr [rdi+1Ch],6E6Fh
mov byte ptr [rdi+1Eh],20h
add rdi,1Fh
mov rcx,rdi
mov rdx,rsi
call qword2hexA (07FF79E371880h)
add rdi,10h
mov dword ptr [rdi],73692068h
mov byte ptr [rdi+4],20h
add rdi,5
fld dword ptr [CR4_P1p23 (07FF79E373728h)]
mov rcx,rdi
xor edx,edx
mov r8d,3
xor r9d,r9d
call St0ToStrA (07FF79E3714B0h)
fstp st(0)
mov rcx,rdi
call StrLengthA (07FF79E371460h)
lea rdi,[rdi+rax]
mov dword ptr [rdi],206C6D20h
add rdi,4
mov rcx,rdi
mov rdx,7FF79E373730h
call StrCopyA (07FF79E371480h)
mov rcx,rdi
call StrLengthA (07FF79E371460h)
lea rdi,[rdi+rax]
mov byte ptr [rdi],0
Biterider
Hi HSE
Funny that we did something similar :thumbsup:
I'll check your version.
Biterider
Hi Biterider!!
Fantastic! That is more powerfull for general use :thumbsup:.
I follow more close GNU-EFI Print function syntax, because I need to replace that to translate some UEFI examples.
HSE
Hi HSE
I'll borrow the GUID representation idea from your implementation. I did not think about that.
Funny that you also thought about implementing escape sequences :thumbsup:
If we adopt the PrintH1 macro, will it change the previous UEFI demos?
Perhaps an additional feature could be changing foreground and/or background colors using an escape sequence for each.
Biterider
Check this YouTube video (https://www.youtube.com/watch?v=qtCY53Zwru4) (posted by Jack (http://masm32.com/board/index.php?topic=10232.0)).
QuoteWhen The Motherboard Comes With a Virus
60,224 views Jul 31, 2022 A UEFI rootkit by the name of cosmicstrand has been detected on several motherboards (images analyzed in the security writeup came from Asus and Gigabyte H81 motherboards) that has the capability to tamper with Windows operating systems installed to any disk, and is persistent upon os resets or hard drive changes.
Quote from: Biterider on July 31, 2022, 04:50:46 PM
I'll borrow the GUID representation idea from your implementation. I did not think about that.
:biggrin: :thumbsup:
Quote from: Biterider on July 31, 2022, 04:50:46 PM
If we adopt the PrintH1 macro, will it change the previous UEFI demos?
In some error messages calling PrintC there are originals "\n", so in that cases an additional line will be added (because PrintC call PrintLn). Anyway, they are 6 lines in Paoloni2010.inc :biggrin:
Hi
Unfortunately I found a macro in the masm32 macros that is also called printf. To avoid conflicts, I renamed the new version to WriteF.
On the bright side, I could easily add a new debug macro now called DbgWriteF that simply outputs the result of WriteF to any debug device.
Example from a recently discussed case
DbgWriteF DBG_COLOR_TEXT, "HtmlHelp Constants", "¦ST¦AT¦ST", pName, 35, pValue
Biterider