-1

Floating point exception core dumped. I am using 64 bit assembly. I think i'm getting the error where I use the div instruction from what I've seen about the error,(people seem to get it when they don't clear RDX) but as i am clearing it with the xor function I don't know whats wrong with my code.

section     .text
global      _start                              ;must be declared for linker (ld)

_start:
mov rdi,1                                  ;tell linker entry point
mov rax,rdi
push rax
jmp loop

loop:
pop rax
cmp rax,19
jle test3
mov rax,1;quit
syscall ;quit

test3:
add rdi,1
push rdi
mov rax,rdi 
xor rdx,rdx
mov rbx,3
div rbx
cmp rdx,0
je fizz
jmp test5

test5:
mov rax,rdi 
xor rdx,rdx
mov rbx,5
div rbx
cmp rdx,0
je buzz
jmp loop 


fizz:
    mov     rdx,5                               ;message length
    mov     rcx,msg                             ;message to write
    mov     rbx,1                               ;file descriptor (stdout)
    mov     rax,4                               ;system call number (sys_write)
    syscall                               ;call kernel
jmp loop

buzz:
    mov     rdx,5                               ;message length
    mov     rcx,msg2                            ;message to write
    mov     rbx,1                               ;file descriptor (stdout)
    mov     rax,4                               ;system call number (sys_write)
    syscall                               ;call kernel
jmp loop


section     .data

msg     db  'fizz',10               
msg2     db  'buzz',10   
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • Yes, `#DE` is the only way on x86 Linux to get a SIGFPE arithmetic exception signal, unless you unmask some actual FP exceptions. Which `div` instruction faults? Use a debugger to find out. Also, how are you assembling + linking and running this? – Peter Cordes Dec 18 '19 at 16:42
  • Are you sure you rebuilt your executable after changing the source? I tried this on my Linux desktop and it just goes into an infinite loop without printing anything. (Your code looks overcomplicated so I didn't try to debug the infinite loop myself e.g. `je` / `jmp` is silly, just use `jne` or fall through; Also a down-counter like `dec ebx / jz fizz` would be more efficient). (I assembled with `nasm -felf64 fizzbuzz.asm` and linked into a static executable with `ld -o fizzbuzz fizzbuzz.o` directly). So this isn't a [mcve] of what you're asking about. – Peter Cordes Dec 18 '19 at 16:46
  • I'm using nasm. Compiling it in the ubuntu terminal and running it – Idealdug Dec 18 '19 at 16:46
  • I'm getting the same now, infinite loop and printing nothing. why does the code not end? it should once rdi gets equal to 20 – Idealdug Dec 18 '19 at 16:51
  • Use a debugger to single-step and find out. IDK why you're using push/pop; that looks weird. Oh and BTW, you're using the wrong register for syscall args; that's why they're always returning `-EFAULT` (use `strace`). You're using 32-bit call numbers and registers instead of 64-bit. – Peter Cordes Dec 18 '19 at 16:53
  • what debugger would you recommend? – Idealdug Dec 18 '19 at 16:54
  • GDB works, but it doesn't have a very nice UI. GDBGUI is usable for asm last I checked. https://www.gdbgui.com. See also the bottom of https://stackoverflow.com/tags/x86/info for debugging tips. (See also my update to my last comment about your system calls being wrong.) – Peter Cordes Dec 18 '19 at 16:55
  • when you say use strace should I just replace syscall with strace? I've been told to use syscall. – Idealdug Dec 18 '19 at 17:01
  • No, `strace` is a debugging tool. Run `strace ./my_program` to see the system calls it makes, with args and return value decoded into meaningful things like `-EFAULT`. – Peter Cordes Dec 18 '19 at 17:20

1 Answers1

1

Your program generates wrong syscalls.

From the System V ABI, the parameters for a syscall are in the following registers: rdi, rsi, rdx, rcx, r8, r9

Also, 1 is for sys_write, 4 is for sys_stat(sys_exit is 60).

Floating Point Exceptions only happen when the divisor is 0 or rdx hasn't been cleared. Since neither are the case, it shouldn't happen.

section     .text
global      _start                              ;must be declared for linker (ld)

_start:
mov r8,1                                  ;tell linker entry point
mov rax,r8; rdi is needed for syscalls, have to use another register 
          ; or save it before preparing to call the kernel
push rax
jmp loop

loop:
pop rax
cmp rax,19
jle test3
mov rax, 60; sys_exit
xor rdi, rdi; clear rdi(exit code)
syscall

test3:
add r8,1
push r8
mov rax,r8 
xor rdx,rdx
mov rbx,3
div rbx
cmp rdx,0
je fizz
jmp test5

test5:
mov rax,r8 
xor rdx,rdx
mov rbx,5
div rbx
cmp rdx,0
je buzz
jmp loop 


fizz:
    mov     rdx,5                               ;message length
    mov     rsi,msg                             ;message to write
    mov     rdi,1                               ;file descriptor (stdout)
    mov     rax,1                               ;system call number (sys_write)
    syscall                               ;call kernel
jmp loop

buzz:
    mov     rdx,5                               ;message length
    mov     rsi,msg2                            ;message to write
    mov     rdi,1                               ;file descriptor (stdout)
    mov     rax,1                               ;system call number (sys_write)
    syscall                               ;call kernel
jmp loop


section     .data

msg     db  'fizz',10               
msg2     db  'buzz',10   

The output is:

fizz
buzz
fizz
fizz
buzz
fizz
fizz
fizz
buzz

You can find syscall numbers in this table here: https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/

Dinu
  • 129
  • 2
  • 6
  • A normal fizzbuzz would also print out numbers for numbers that aren't a multiple of 3 or 5. See [How do I print an integer in Assembly Level Programming without printf from the c library?](//stackoverflow.com/a/46301894) (or increment ASCII digits). The OP's code doesn't do even attempt to do that, so yes +1 for getting the OP's code to work. (Although it's still very inefficient and clunky. e.g. there's a `jmp test5` that's a no-op; execution would fall through to there anyway. And most of the instructions in the `fizz` and `buzz` blocks are the same.) – Peter Cordes Dec 21 '19 at 19:52