How to make a correct conclusion to the console?

.386 .model flat, stdcall option casemap :none include includes\masm32.inc include includes\msvcrt.inc include includes\win32k.inc include includes\kernel32.inc include includes\macros\macros.asm include includes\user32.inc includelib includes\masm32.lib includelib includes\kernel32.lib includelib includes\win32k.lib includelib includes\msvcrt.lib includelib includes\user32.lib .data y db -15 Pi dq 3 tpt db 'y=%d, Pi =%d', 10,0 .code start: invoke crt_printf, ADDR tpt, [y], [Pi] invoke crt__getch invoke crt_exit,0 end start 

Displays the wrong data

  • What data outputs? - insolor
  • 241 and 0.00034. @insolor - Raccoon

1 answer 1

Your program cannot output 0,00034 , unless of course you have a different specifier instead of the second %d . I have y=241, Pi =196608 .

Why displays not what you need?

Under the disassembler, we look at what the assembler generated us:

 .text:00401000 ; =============== SUBROUTINE ======================================= .text:00401000 .text:00401000 ; Attributes: noreturn .text:00401000 .text:00401000 public start .text:00401000 start proc near .text:00401000 push dword_403005 .text:00401006 push dword_403001 .text:0040100C push 0 .text:0040100E mov al, byte_403000 .text:00401013 movzx ax, al .text:00401017 push ax .text:00401019 push offset Format ; "y=%d, Pi =%d\n" .text:0040101E call ds:printf .text:00401024 add esp, 10h .text:00401027 call ds:_getch .text:0040102D push 0 ; Code .text:0040102F call ds:exit .text:0040102F start endp ... .data:00403000 byte_403000 db 0F1h ; DATA XREF: start+Er .data:00403001 dword_403001 dd 3 ; DATA XREF: start+6r .data:00403005 dword_403005 dd 0 ; DATA XREF: startr .data:00403009 ; char Format[] .data:00403009 Format db 'y=%d, Pi =%d',0Ah,0 ; DATA XREF: start+19o 

First, the assembler honestly puts two dvds on the stack (i.e., one qword , the variable size specified in the source code using dq ). Further, for some reason, 0 is put on the stack, then the original byte variable expands to a single word, and without taking the sign into account ( movzx - move with finishing on the left with zeros), then puts the word onto the stack, and this single word automatically expands to double, again same without a sign. After that the address of the format string is put on the stack, and the printf function is called.

After calling the function, the stack is aligned (by convention cdecl ) by the amount of the parameters sent to the stack. In this case, it is aligned to 16 bytes (10h), although it should be aligned to 5 push * 4 bytes = 20 bytes.

Everything looks rather strange. It seems that macmas macros do not always take into account that we are working in 32-bit mode, and not in 16-bit mode.

We try to replace db and dq with dd , and build. The result is y=-15, Pi =3 , which is what was required. The disassembler also shows the expected code:

 .text:00401000 public start .text:00401000 start proc near .text:00401000 push dword_403004 .text:00401006 push dword_403000 .text:0040100C push offset Format ; "y=%d, Pi =%ld\n" .text:00401011 call ds:printf .text:00401017 add esp, 0Ch .text:0040101A call ds:_getch .text:00401020 push 0 ; Code .text:00401022 call ds:exit .text:00401022 start endp 

What to do if you want to display exactly the byte and the quad word?

Using qualifiers specifically designed for byte and for the quadruple word ( tpt db 'y=%hhd, Pi =%lld', 10,0 ) does not help by itself. Therefore, we will try to transfer the parameters manually, not relying on the work of standard macros:

 .data y db -15 Pi dq 3 ; %lld обязательно нужно указать, чтобы printf знал, что на стеке лежит два двойных слова tpt db 'y=%d, Pi =%lld', 10,0 .code start: push dword ptr [Pi+4] push dword ptr [Pi] movsx eax, [y] ; Расширяем байт до двойного слова с учетом знака push eax push offset tpt call crt_printf add esp, 10h ; 4 пуша по 4 байта = 16 = 10h invoke crt__getch invoke crt_exit,0 end start 

Print out:

 y=-15, Pi =3 

Now, if we go back to what we saw in the process of disassembling the first option - macros should be able to put qword correctly on the stack, so it’s enough to prepare in advance only the byte for output, and invoke function via invoke :

 movsx eax, [y] ; Расширяем байт до двойного слова с учётом знакового бита invoke crt_printf, addr tpt, eax, [Pi] 

The result will also be

 y=-15, Pi =3