How do you use printf in x86 assembly in Visual Studio 2017?

3

Unhandled exception at 0x777745BA (ntdll.dll) in MASM1.exe: 0xC0000005: Access violation writing location 0x00000014. I'm using x86 assembly in visual studios 2017 and it keeps returning this error

I have included all of the libraries and installed windows 10 sdk. I am basically stumped as of why this is returning this error on line 21. It even opens a blank window and then immediately closes it returning the error.

            .586
            .MODEL FLAT
            .STACK 4096
            includelib libcmt.lib
            includelib libvcruntime.lib
            includelib libucrt.lib
            includelib legacy_stdio_definitions.lib
            EXTERN  printf:PROC
            EXTERN  scanf:PROC

            .DATA
                format BYTE "Enter a number", 0

            .CODE

            main PROC
                sub esp, 4
                push offset format
                call printf
                add esp, 4
                ret
            main ENDP
            END

I created a VS 2017 C++ project generating a Win32 console program. In the project properties / Linker / Advanced / entry point option I have set the entry point to main.

visual-studio
assembly
x86
masm
asked on Stack Overflow May 12, 2019 by Mike D • edited May 12, 2019 by Michael Petch

2 Answers

5

You have a sub esp,4 and a push before the call, so to restore the stack pointer to point at the return address you need to add esp,8 before ret, instead of add esp, 4

(printf is a varargs function so it does not pop its own args off the stack. It uses a cdecl calling convention.)

Or better, remove sub esp,4.

32-bit Windows only maintains 4-byte stack alignment, so you don't need to do anything extra with ESP before a push/call to get the stack pointer re-aligned before a call. And you're not using that 4 bytes you reserved for anything.


Update: MichaelPetch observed that your program is probably crashing inside printf, because you called it without initializing libc. Probably you're building your program with this function as the entry point, not called from the normal C startup code. (And that the Visual Studio debugger wrongly reports the crash as being on the line after the call, instead of where the crash actually happened.)


Your error message appears to still be from the first version of the question, where you left out the ret! In that case, execution just falls of the end of main into whatever bytes are next, decoding them as instructions. Probably zeros.

00 00 decodes as add [eax], al, and eax holds 14 from the return value of printf. (printf returns the number of characters printf, and your format string is 14 bytes long).

But the error message is about writing address 0x14, which is decimal 20 (16 + 4), so my first guess doesn't quite add up. If you want to know, use a debugger to find the instruction that actually faults, and look at register values. You may have to use the disassembly view instead of asm source view, especially for the version where you fall off the end of main.


Probably you get no output on screen if stdout is line-buffered, and your printf format string doesn't end with a newline. So the string is still sitting in the IO buffer when you crash. (Although IIRC, printf on Windows isn't like that, and does fflush() the buffer even if it doesn't end with a newline.)

Use puts to print a fixed string (no % conversions) and append a newline. i.e. puts(x) is like printf("%s\n", x).

answered on Stack Overflow May 12, 2019 by Peter Cordes • edited May 12, 2019 by Peter Cordes
4

This is the solution proposed by the OP in an edit to their question:

I solved the problem by clearing the linker->advanced->Entry point option which I had set to main in the project properties.

As @PeterCordes suggests in his answer - the best solution to fix the stack related issue is to remove the sub esp, 4.

answered on Stack Overflow May 12, 2019 by Michael Petch • edited May 14, 2019 by Michael Petch

User contributions licensed under CC BY-SA 3.0