Converting C to NASM assembly with segmentation issue
Asked Answered
G

3

6

I'm trying to get this c code:

main()

 {int x, y, count ;

  count = 0 ;
  x = 10 ; 
  y = 2 ;
  while (y < x)
    { x = x + 1 ;
      y = y + 2 ;
      count = count + 1 ;
     } 

    printf(“ It took %d iterations to complete loop. That seems like a     lot\n”,count) ;
}

to its NASM equivalent which I have this so far:

segment .data

out1    db "It took ", 0
out2    db "%i ", 0
out3    db "iterations to complete the loop. That seems like a lot.", 10, 0

segment .bss

segment .text

global     main
extern printf

main:

    mov    eax, 0        ;count
    mov    ebx, 10        ;x
    mov    ecx, 2        ;y

    jmp     lp

    mov    eax, 0
    ret

lp:
    cmp    ecx, ebx    ;compare y to x
    jge    end        ;jump to end if y >= x
    add    eax, 1
    add    ebx, 1
    add    ecx, 2
    jmp    lp

end:

    push    out1
    call    printf

   push    eax
   push    out2
   call    printf

   push    out3
   call    printf

I keep getting a segmentation fault and I don't understand why it keeps happening. I've tried adding in print statements everywhere and cannot find where the fault is located. Any advice would be great! Thank you!

Gaelic answered 29/4, 2015 at 22:11 Comment(3)
Your asm seems okay to me.Chaechaeronea
Do you have a ret instruction after the printfs?Stollings
yes i've tired that it didn't take care of the segmentation problem :(Gaelic
S
0

I think you are not following the calling convention for printf (it's cdecl IIRC).

  1. the caller must clean the stack after the call
  2. and eax is clobbered by the first call to printf with it's return value

Number one will cause trouble when returning from main. Actually, there is no ret instruction after the printfs which causes the execution to go on until something goes wrong :)

Add the following after printing:

   add     esp, 16  ; Fix stack, usually it's done after each call
                    ; with the appropiate values.
                    ; In this way (one fixup for many calls) stack
                    ; grows unnecessarily
   xor     eax, eax ; set return value to 0
   ret              ; Return from main

Although, this does not take care of issue number two.

Stollings answered 29/4, 2015 at 22:21 Comment(4)
Thanks that actually helped quite a bit I'll see if it works.Gaelic
Diego, since this is a stand-alone assembly program, there is no main and no need to return. What is needed is to make a syscall to exit to cleanup on program termination. The exit code is set in ebx, the x86 syscall for exit is 1 (see: /usr/include/asm/unistd_32.h) and goes in eax, then the kernel is called to execute the command int 0x80 or int 80h.Grand
@DavidC.Rankin: Making an exit system call instead of returning is obviously fine, but this program clearly does have a main function. Most assembly programs linking to the standard C library will have one.Rakia
Could you guys also look at this code for me really quick as well? It also having a segmentation issue which I'm not able to figure out. Its a similar exercise where we take a c program and create a nasm program from it. #29957067Gaelic
M
0

Updated and complete example:

segment .data
out1    db      "It took %d iterations to complete loop. That seems like "
        db      "a lot.", 0aH, 00H
segment .bss
segment .text
        global  main
        extern  printf
main:   xor     eax, eax
        mov     ebx, 10
        mov     ecx, 2
loop0:  inc     ebx
        add     ecx, 2
        inc     eax
        cmp     ecx, ebx
        jl      loop0
        push    eax
        push    offset out1
        call    printf
        add     esp, 8
        xor     eax, eax
        ret
        end
Malca answered 29/4, 2015 at 22:59 Comment(1)
i'm still getting the segmentation fault with the changesGaelic
G
0

If you haven't got it sorted out yet, the issue is due to eax getting thrashed on your printf call. How to fix? Save it to a buffer before the first printf call and load eax before the second. E.g. add:

segment .bss

buffer resd  1          ; reserve 32 bit buffer
...
mov     [buffer], eax   ; save eax in the buffer

push    out1
call    printf

mov     eax, [buffer]   ; load eax from the buffer

push    eax
push    out2
call    printf

push    out3
call    printf

xor     ebx, ebx         ; exit nicely 
mov     eax, 1
int     0x80

Use/Output

$ ./bin/pt
It took 8 iterations to complete the loop. That seems like a lot.
Grand answered 29/4, 2015 at 23:36 Comment(1)
I'm not sure I'd waste time and effort coding up a buffer for it when you have a perfectly good stack just sitting around, waiting to be used :-) In other words, push eax, pop eax.Minorca

© 2022 - 2024 — McMap. All rights reserved.