baseman101
baseman101

Reputation: 362

Assembly Win32 _printf Code Crashing

I am new to the NASM assembler, and have attempted to write my own assembly code. Upon compiling, I have not received any errors, but on runtime, the code crashes. While debugging, it seems that the code is crashing at either the push or _printf calls.

I've commented my code to make it a bit more readable.

global _main
extern _printf  

section .text
_main:
    jp _loop ;jump to loop

_loop: 
    mov ebx, [a] ;move double word 'a' into register ebx
    inc ebx ;increment register ebx
    mov [a], ebx ;move contents of ebx into double word 'a'
    add ebx, '0' ;add char 0 (0x30)
    push ebx ;push ascii character on to stack
    push format ;push format string on to stack
    call _printf ;call print function
    cmp dword [a], 10 ;compare if value of a is equal to 10
    jne _loop ;loop if not equal to 10
    ret ;return if equal to 10

a:
    dd 0 ;initialize dword as 0

format:
    db "%i", 0 ;format string for printf

Thanks in advance! I hope this isn't too nooby.

Upvotes: 2

Views: 205

Answers (1)

icktoofay
icktoofay

Reputation: 129119

I tried compiling and running your code myself (alas not on Windows; who says assembly isn’t portable?), and it crashed not on the call _printf or push lines, but on mov [a], ebx. The permissions on the .text segment are read and execute, but not write. a is in .text, and mov [a], ebx tries to write to a, so it tries to write to a non-writable section, and the program crashes with a general protection fault. The way you’d get around this is by putting a in a different section, e.g. .data.

That should solve your (first) problem, but there’s two more things you ought to know about:

  1. You have jp _loop as the first instruction of _main. That jumps to _loop if the parity flag is set. I don’t think you actually meant to test the parity flag; in this case, it either jumps there, or the test fails and it falls through to _loop anyway. You could do an explicit jmp, but it’s really not necessary. If I were you, I’d just omit that instruction entirely so _main and _loop coincide.

  2. I believe _printf uses the C calling convention, where the caller is responsible for popping the arguments (unlike the stdcall used for Windows API functions); you’re pushing lots of things onto the stack, and never popping them. That means the more iterations you do, the more stack memory you’re using. That doesn’t seem like what you want. Furthermore, you later ret, which, since you pushed things in the mean time, won’t return to the right place since the top of the stack isn’t the return address. You’ll want to pop or adjust the stack pointer explicitly after calling _printf:

    add esp, 8
    

    Alternatively:

    1. Before your loop, reserve the appropriate amount of stack space:

      sub esp, 8
      
    2. After your loop, release that stack space:

      add esp, 8
      
    3. Rather than pushing arguments, modify the data already on the stack:

      mov [esp+4], ebx
      mov [esp], format
      

Upvotes: 2

Related Questions