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

2

5

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.

Nmr answered 12/5, 2019 at 15:23 Comment(14)
Yeah I've used ret already and that didn't fix anythingNmr
Then update your question with the version that has a ret; this version has an obvious huge bug.Geriatrician
Really, you still get writing location 0x00000014 as the error with ret? On which instruction? Is it inside printf, or after main returns?Geriatrician
Just did sorry about that. Any other suggestions? I have been using the debugger this entire time trying to figure this out and can't seem to find the solution to the errorNmr
It specifically says line 19 which is when i add 4 back to esp.Nmr
That instruction doesn't write memory, it only modifies a register, so it's impossible for that instruction it to fault that way. Use the disassembly view in your debugger to see actual instructions that run, not just the asm source.Geriatrician
The caller is responsible for cleaning up arguments to printf. So you need to add esp, 8 before returning to clean up both the pushed format argument and to adjust for the sub esp, 4Conners
I'm a bit surprised this assembles and links. I would have thought you would need .MODEL FLAT, C for it to properly link main since it really should resolve to _main. You say you are using Visual Studio 2017. Are you using custom assemble and link commands and if so what are the commands you are using to assemble and link? I have a suspicion you didn't create a VS2017 MSVC project with the IDE the normal way (by adding MASM as a build dependency) and then add an ASM file with this code.Cosec
I have a hunch that you have managed to circumvent running the C runtime start up code (so printf won't run properly) and you have managed to force the entry point for your program to be main (with a command line option?). This is on top of the fact add esp, 4 should be add esp, 8. I was able to reproduce your problem by forcing main to be the entry point by linking with the /ENTRY option. The other possibility is that what you are showing here for assembly code is not what you are actually using.Cosec
I can only recommend at a very minimum. Change .MODEL FLAT to .MODEL FLAT, C then change the ADD ESP, 4 (after printf) to ADD ESP, 8 and if you are linking with /ENTRY remove that option. That's what I recommend as long as you don't show your assembling and linking commands (and all the options).Cosec
Don't edit your question to give a solution. It is allowed and encouraged to create an answer to your own question.Cosec
Did you also by chance modify project properties / Microsoft Macro Assembler / Advanced / Calling Convention so that it was set to Use C-style Calling Convention (/Gd) (/Gd)?Cosec
@MichaelPetch which calling convention we use for self code no matter here. we can not change calling convention of external function (printf)Finch
@Finch : That's not why I asked the question. Changing the calling convention also changes whether MASM by default uses underscores or not. The code as posted doesn't use .MODEL FLAT, C so for this code to assemble and link without undefined references something external had to be set to override the default behaviour. For instance without changing the default behavior EXTERN printf:PROC would have had to have been EXTERN _printf:PROC and main PROC would have had to have been _main PROC etc.Cosec
G
6

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).

Geriatrician answered 12/5, 2019 at 15:38 Comment(4)
The debugger will erroneously show the error on line 21 (the add esp, 4) when in fact it actually occurred inside the printf call and the way I have reproduced it (right down to the value 0x00000014) is to prevent the C runtime startup code from being executed (by making the entry point for the program main) rather than what is the default entry point in the C runtime code. My opinion is the problem is more about how they are assembling and linking which is the info they don't provide :(Cosec
Sorry for not providing that my project build dependencies is set to masm check box. My linker advance entry point is set to main. The linker system is still console. I'm not sure what other information you want me to provide about what Im linkingNmr
@MikeD: Use @username to notify people you're replying to. You're replying under my answer, so I get a ping, but MichaelPetch probably didn't. That said, putting that info in your question would be a start. Your normally want the entry point to be the CRT (C Runtime Startup) start code, so it can run the library init functions before calling your main.Geriatrician
@Michael Petch and Peter Cordes It was the entry point i removed the entry point main and thats what fixed it. Thank you guys for your time and info on this. Y'all have helped me a lot. Thank you againNmr
C
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.

Cosec answered 12/5, 2019 at 15:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.