0

I'm learning some basic arithmetic using NASM on Linux. I need to divide two numbers using variables NUMBER1 and NUMBER2. My code works if I type in actual value instead of variables. For example if I type in '6' instead of NUMBER2 and '2' instead of NUMBER1, the program does division and gives me answer of 3. Running code with variables gives FLOATING EXCEPTION (CORE DUMPED). could please explain how correctly use variables in this code? While debugging, I see that the problem is in DIV line. Thank you !

 section .text

global main ;must be declared for using gcc

main: ;tell linker entry point
mov ax,[NUMBER2]
sub ax, '0'
mov bl, [NUMBER1]
div bl
add ax, '0'
mov [res], ax
mov ecx,msg
mov edx, len
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
nwln
mov ecx,res
mov edx, 1
 mov ebx,1 ;file descriptor (stdout)
 mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel

section .data
NUMBER1: dw 2
NUMBER2: dw 6
msg db "The result is:", 0xA,0xD
len equ $- msg

segment .bss
res resb 1
Karlos
  • 39
  • 7
  • `sub ax, '0'` -- why is this here? You stored a raw 6 in the data segment, not an ascii character 6 – harold Jan 30 '18 at 21:38
  • I'm using this example from NASM documentation, I believe it's because of remainder. – Karlos Jan 30 '18 at 21:44

1 Answers1

1

Because given example is supposed to process ASCII codes for numbers, not numbers themselves. If you enter 6 instead of '6', 6 - '0' evaluates to 65494 (not 6). If you try to divide further by 2, processor is unable to store quotient in lower half of ax register.

If you do not intend to output result to console and only try to learn how division with one byte integer works using assembler, pick your favourite debugger, place breakpoint after division operation and enjoy your result.

section .text

global main ;must be declared for using gcc

main: ;tell linker entry point
mov ax,[NUMBER2]
mov bl, [NUMBER1]
div bl
nop ; quotient at al, remainder at ah
; remove nop instruction if your code is larger than few lines
; place output code here

section .data
NUMBER2: dw 6 ; dw means two bytes
NUMBER1: db 2 ; db means one byte

segment .bss
res resb 1
BalticMusicFan
  • 653
  • 1
  • 8
  • 21
  • 1
    Why do you have a `nop` instruction after `div`? Put a label after `div` if you want to make it easy to set a breakpoint, or just set a breakpoint before `div` and single-step over it (so you can see register values before / after it runs). But yes, the answer is that `sub` wraps, then unsigned `div` of a large number by 2 overflows the quotient, which raises #DE, [causing Linux to deliver SIGFPE](https://stackoverflow.com/questions/16928942). (Because unlike most integer operations, `div` overflow traps instead of wrapping.) – Peter Cordes Jan 30 '18 at 23:22
  • @PeterCordes `nop` instruction is a placeholder for breakpoint and it is usually shorter to write than any label. – BalticMusicFan Jan 30 '18 at 23:35
  • But it assembles to an instruction in the executable! If you want compact source instead of clean / efficient asm for some reason, then `bp:` is also short. Plus it lets you type `b bp` instead of having to find the address or line number of the `nop` (if you're using text-mode gdb so you can't just click on unlabeled instructions). – Peter Cordes Jan 30 '18 at 23:46
  • @PeterCordes I edited my answer about that instuction. I am more familiar with Windows assembly debugging than Linux, so your gotcha. – BalticMusicFan Jan 31 '18 at 00:17
  • 2
    You never need the `nop`. Even if you make an incomplete program with garbage following the `div`, you can single-step past the `div` so execution stops at whatever comes next. Having a NOP there is not useful or important. If you want to put anything there, put `xor ebx,ebx` / `mov eax,1` / `int 0x80 ; sys_exit(0)` – Peter Cordes Jan 31 '18 at 00:43
  • thank you for your comments. You were right, I confused myself with ASCII and actual numbers. – Karlos Feb 01 '18 at 00:24