assemblyx86segmentation-faultnasm

Program runs forever and doesn't print anything to the console


i am trying to build a program that would print a value of each bit in AL into the console, because i want to see the time (in seconds) stored in eax. GDB says my program has received signal SIGSEGV, which indicates segmentation fault.

I have realized now that i had used pop instruction in my loop and push instruction before the loop, which resaulted in segmentation fault.

I have fixed it simply by moving the data to edi.

But now my fixed program doesn't output anything to the console. It seems like it runs forever.

Does anyone have any idea why?

Thanks a lot! Feel free to ask me questions about my shitty code.

SECTION .data
linefeed db 0xA,0xD

SECTION .bss

SECTION .text
global _start

_start:

mov eax,13 
int 80h 

;push eax 
mov edi,eax
mov bl,1
mov cl,0 

bitmaska:

shl bl,cl 

and al,bl 

shr al,cl 

shr bl,cl 

add al,48

mov edx,1 
movzx ecx,al 
mov ebx,1
mov eax,4
int 80h

;pop eax
 mov eax,edi

inc cl

cmp cl,8
jnz bitmaska 

konec:
mov edx,1
mov ecx,linefeed
mov ebx,1
mov eax,4
int 80h

mov ebx,0
mov eax,1
int 80h

Solution

  • Express edit to address more issues from a comment. Currently my browser doesn't allow writing comments

    mov eax,13
    int 80h
    

    There's trouble with that sys_time that is supposed to return in EAX the time as the number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). You forgot to initialize the EBX argument. If EBX happened to be non-zero, then the service would have tried to additionally store the result in whatever memory EBX was pointing to. That's a good reason for a segmentation error! You should always zero the EBX register with this service:

    xor   ebx, ebx             ; Don't need a copy in memory
    mov   eax, 13              ; sys_time
    int   80h                  ; -> EAX
    

    But, if you did want a copy in a memory location, then just reserve room for it. Preferrably in the .bss section, but in the .data section would be fine too. You create it with: MyCopyOfTheTime dd 0 when in the .data section, or with MyCopyOfTheTime resd 1 when in the .bss section.
    The actual retrieval then requires EBX pointing to this doubleword:

    mov   ebx, MyCopyOfTheTime ; Want a copy in memory
    mov   eax, 13              ; sys_time
    int   80h                  ; -> EAX
    

    You can use this copy from memory with the usual instructions. You can read from it with eg. mov eax, [MyCopyOfTheTime], and you write to it with eg. mov dword [MyCopyOfTheTime], 0.


    The write operation within the loop messes with the other registers that your loop depends on! Moreover you didn't supply in ECX an address for this system call. And once it will work, you will notice that the output is in the reverse order because you begin at the lowest bit. The binary representation must have the most significant bit on the left side, so start at the highest bit.

    I would suggest that you don't output while being in the loop, but store to memory, and then in the end you can output everything in one go.
    To this effect you change the linefeed definition to be:

    buffer   db '????????'
    linefeed db 10
    

    The 8 question marks are place-holders for your actual '0' and '1' characters. The final output then becomes:

    konec:
     mov   edx, 9
     mov   ecx, buffer
     mov   ebx, 1
     mov   eax, 4
     int   80h
    

    Now the core loop should be a simple one. No need to shift that many times by CL:

     mov   ebx, eax
     mov   edi, buffer
     mov   ecx, 8
    bitmaska:
     mov   al, 48
     shl   bl, 1       ; Shift a bit out into the carry
     adc   al, 0       ; Add that bit to the value 48
     stosb             ; Store '0' or '1' in the buffer
     dec   ecx
     jnz   bitmaska 
    

    If the reverse order was intentional, then just replace shl bl, 1 by shr bl, 1.