Simple assembly program arithmetic error - nasm

I tried to write a program that adds the digits of a 16-bit number "broj" and stores the result in a location named "rez".
Here's my code:
SECTION .data
broj DW 25326
SECTION .bss
rez RESW 1
SECTION .text
global _start
_start:
MOV CX, 10
MOV AX,[broj]
skok:
DIV CX --> result in AX, remainder in DX
ADD [rez],DX
MOV BX,AX -->move the result of the last division
JNZ skok
MOV EAX,1
MOV EBX,0
int 80h
This produced an "arithmetic error", however, my assembly-debugging skills are more than limited.
I used kdbg under Mint.

DIV CX will divide the 32-bit value in DX:AX by CX. So you need to clear DX before the DIV (e.g. XOR DX,DX) to avoid getting a quotient that's larger than 16 bits.

Related

Converting C code to x86-64 bit Assembly?

I am trying to create a random letter generator for my string and I've been given a C code and will have to convert it into Assembly language for my program. I'm doing this in x86-64 bit NASM assembly language. I'm supposed to be using only system calls and not C/C++ function calls.
Here's the C/C++ code that I've got to convert:
int genran(int x,int y)
{
int a = 0;
a = a + x * 1103515245 + 12345;
return (unsigned int)(a / 65536) % (y + 1);
}
I am new to Assembly and any help is appreciated, here's what I've got so far. I know its somewhat wrong but I will be working on improving it:
section .data
string db "The random string is generated below: "
len_string equ $-string
a dd 0
x dd ?
y dd ?
rem dd 0
section .bss
string_buff resb 21 ;Our string's length is 20 characters
section .txt
global main
main:
mov rax, 1
mov rdi, 1
mov rsi, string
mov rdx, len_string
syscall
mov rax, a
mov rbx, x ;we have to come up with a value of x?
mul rbx, 1103515245
add rbx, 12345
mov rax, rbx
div rax, 65536
mov rdx, y ;we have to come up with a value of y?
add rdx, 1
;mod rax, rdx
;ret
exit:
mov rax, 60
xor rdi, rdi
syscall
mov rax, rbx
div rax, 65536
Please read the instructions; this doesn't exist. div is an opcode that only takes one argument. The code should look like
mov rax, rbx
xor rdx, rdx ; Div takes rdx:rax as an implicit 128 bit argument.
mov rcx, 65536
div rcx
At this skill level I don't recommend trying to use read or write system calls. I very much instead recommend calling the C standard library until you get the hang of it. read and write have too many gotchas. You will want to write them once and include them in a mini-library any more assembly work you do.
We can skip read by taking argument off the command line as follows:
mov rbx, [rsp + 16] ; argv[1]
Unless I'm very much mistaken, the first thing on the stack is argc, and then argv[0], then argv[1], ...

printing numbers in nasm

I have written an assembly code to print numbers from 1 to 9 but the code only prints 1 and no other element other than 1 is printed and only one output is received.It means that the loop is also not being run. I cant figure out what is wrong with my code.
section .bss
lena equ 1024
outbuff resb lena
section .data
section .text
global _start
_start:
nop
mov cx,0
incre:
inc cx
add cx,30h
mov [outbuff],cx
cmp cx,39h
jg done
cmp cx,39h
jl print
print:
mov rax,1 ;sys_write
mov rdi,1
mov rsi,outbuff
mov rdx,lena
syscall
jmp incre
done:
mov rax,60 ;sys_exit
mov rdi,0
syscall
My OS is 64 bit linux. this code is built using nasm with the following commands : nasm -f elf64 -g -o num.o num.asm and ld -o num num.asm
Answer rewritten after some experimentation.
There two errors in your code, and a few inefficiencies.
First, you add 0x30 to the number (to turn it from the number 1 to the ASCII 1). However, you do that increment inside the loop. As a result, your first iteration cx is 0x31, second 0x62 ("b"), third 0x93 (invalid UTf-8 sequence) etc.
Just initialize cx to 0x30 and remove the add from inside the loop.
But there's another problem. RCX is clobbered during system calls. Replacing cx with r12 causes the program to work.
In addition to that, you pass the buffer's length to write, but it only has one character. The program so far:
section .bss
lena equ 1024
outbuff resb lena
section .data
section .text
global _start
_start:
nop
mov r12,30h
incre:
inc r12
mov [outbuff],r12
cmp r12,39h
jg done
cmp r12,39h
jl print
print:
mov rax,1 ;sys_write
mov rdi,1
mov rsi,outbuff
mov rdx,1
syscall
jmp incre
done:
mov rax,60 ;sys_exit
mov rdi,0
syscall
Except even now, the code is extremely inefficient. You have two compares on the same condition, one of them branches to the very next instruction.
Also, your code would be much much much faster and smaller if you moved the breaking condition to the end of the code. Also, cx is a 16 bit register. r12 is a 64 bit register. We actually only need 8 bits. Using larger registers than needed means all of our immediates waste up space in memory and the cache. We therefor switch to the 8 bit variant of r12. After these changes, we get:
section .bss
lena equ 1024
outbuff resb lena
section .data
section .text
global _start
_start:
nop
mov r12b,30h
incre:
inc r12b
mov [outbuff],r12b
mov rax,1 ;sys_write
mov rdi,1
mov rsi,outbuff
mov rdx,1
syscall
cmp r12b,39h
jl incre
mov rax,60 ;sys_exit
mov rdi,0
syscall
There's still lots more you can do. For example, you call the write system call 9 times, instead of filling the buffer and then calling it once (despite the fact that you've allocated a 1024 bytes buffer). It will probably be faster to initialize r12 with zero (xor r12, r12) and then add 0x30. (not relevant for the 8 bit version of the register).

Reading user input as an integer

I wrote an Assembly program (x86_64 Linux NASM) that prints an integer to console, based in the algorithm suggested my the comments in this post, which is basically this:
divide number x by 10, giving quotient q and remainder r
emit r
if q is not zero, set x = q and repeat
All works just fine under the following script:
section .bss
integer resb 100 ; it will hold the EOL
intAddress resb 8 ; the offset
section .text
global _start:
_start:
mov rax, 567
call _printProc
mov rax, 60
mov rdi, 0
syscall
_printProc: ; here goes the algorithm described above.
After compiling it, the number 567 gets printed on the screen (console).
But if I try to do the same but allowing the user to input the number to be printed as integer I don't get what expected. Well, to do this I made the following changes (the algorithm stays the same):
section .bss
integer resb 100 ; it will hold the EOL
intAddress resb 8 ; the offset
number resb 100
section .text
global _start:
_start:
; getting user input
mov rax, 0
mov rdi, 0
mov rsi, number
mov rdx, 100
syscall
mov rax, [number] ; passing the content at address number into rax
call _printProc
mov rax, 60
mov rdi, 0
syscall
_printProc: ; here goes the algorithm described above.
But in this case if I type 567 I get 171390517. In fact, if I type
0, I get 2608
1, I get 2609
2, I get 2610
and so on.
I'd appreciate if some of you have an idea about what is the problem in the second case and how could be fixed.
what happends when you call this
; getting user input
mov rax, 0
mov rdi, 0
mov rsi, number
mov rdx, 100
syscall
is, that your entry ( e.g. "1004") is written to the memory at "number", character per character. Now you have the exact opposite problem you intended to solve:
"how to convert an ASCII string into binary value"
the algorithm for this new problem could look like this:
(assuming char_ptr points to the string)
result = 0;
while ( *char_ptr is a digit )
result *= 10;
result += *char_ptr - '0' ;
char_ptr++;

Displaying a number - assembly code not working Linux, x64 (NASM) [duplicate]

This question already has answers here:
Displaying a number in x86-64 assembly with only Linux system calls [duplicate]
How do I print an integer in Assembly Level Programming without printf from the c library? (itoa, integer to decimal ASCII string)
(5 answers)
Closed 2 years ago.
I am learning assembly on Linux (NASM) x64 machine (I don't have access to 32 or 16 bit machine), and I am trying to display number on screen (reverse of number according to code but that's a start).
Number is predefined in section .data -> num.
I am quite a newbie at assembly programming and due to the lack of material on x64 assembly (really, cant find much, and all I was able to find was quite confusing) I am unable to resolve the issue.
The issue is that the code compiles an links with no errors/warnings, but it just displays some spaces (not even newline). If I remove the call _newl code from _disprem, those spaces are also gone. There is not even segment fault or something.
By the way, algorithm to get the remainder (to get the digits in a number) is num - (num / 10) * 10
section .data
num: dq 102 ;my default number to get the reverse of (for now)
nl: db 0x0a
nlsize: equ $-nl
ten: dq 10
section .bss
rem: resq 1
remsize: equ $-rem
section .text
global _start
_start:
cmp qword [num], 0
jng _exit ;jump to _exit if num is not greater than 0
mov rax, [num] ;move the number to rax
mov rbx, [num] ;move the number to rbx as well so that i have original number in register to subtract and get the remainder
mov rcx, [ten] ;move 10 to rcx to be the divisor
div rcx ;divide number in rax by 10
mov [num], rax ;get the quotient to get the remaining number for quotient
mul rcx ;multiply number in rax by 10
sub rbx, rax ;subtract rbx - rax and store the value in rax (right?)
mov [rem], rbx ;get the remainder from rax. this must be done right after div (WHY??????????)
call _disprem ;call _disprem to display the remainder... call returns the flow back to the caller right?
jmp _start ;get to the loop again
_exit:
mov rax, 60
mov rdi, 0
syscall
_newl:
mov rax, 1
mov rdi, 1
mov rsi, nl
mov rdx, nlsize
syscall
ret
_disprem:
mov rax, 1
mov rdi, 1
add qword [rem], 0x0000000000000030 ;since the rem variable is quadword (64 bit)
mov rsi, rem
mov rdx, remsize
syscall
sub qword [rem], 0x0000000000000030 ;get me my original number back plz thanks
call _newl
ret

nasm x86 find largest and smallest and store in a register

So far I understand how to get the largest number and store it in a register but I am unsure how to continue to get the smallest number? Any help would be much appreciated, or even a more efficient way of doing what I am currently doing. I am trying to store largest number in ax and smallest number in dx
section .data
A dw 1
B dw 3
C dw 8
D dw 5
section .bss
section .text
global _start
_start: mov eax,0 ;clear registers
mov ecx,3
mov esi,A
mov ax, [esi]
add esi,2
again: cmp ax,[esi]
jg cont
mov ax,[esi]
cont: add esi,2
dec ecx
cmp ecx,0
jnz again
exit: mov eax,1
mov ebx,0
int 80h
The way I would do it would to add another comparison after testing
if the current value is greater than the current largest (stored in ax), which would test if the current element is smaller than the current smallest (stored in dx). You would also need to initially set dx to be the same as the first element.
I've added the initial setting of the dx register and an extra section "isSmaller" which performs the check and sets the dx register if the current value being checked is smaller than the value stored in dx.
section .data
A dw 1
B dw 3
C dw 8
D dw 5
section .text
global _start
_start: mov eax,0 ;clear registers
mov ecx,3
mov esi,A
mov ax, [esi] ; Initially set largest
mov dx, [esi] ; and initial smallest
add esi,2
again: cmp ax,[esi]
jg isSmaller
mov ax,[esi]
isSmaller: cmp dx, [esi]
jl cont
mov dx, [esi]
cont: add esi,2
dec ecx
cmp ecx,0
jnz again
exit: mov eax,1
mov ebx,0
int 80h

Resources