NASM Forum > Programming with NASM
How to sum 2 numbers (in Gnu/linux assembly x80_64 & Nasm)?
Frank Kotler:
But he is!
Using a 64 bit syscall (1) with int 80h looks like a problem, Try 4!
Best.
Frank
Ferran:
Ok, I did some changes and I'm still searching solutions to convert a decimal number to a printable string. I can't find the post of @federicopisarra about it.
The last one is using the function dec2stru from BASELIB(c) - owned by stressful, but it don't works to me.
The scripts now is this:
--- Code: ---;------------------------------------------------------------------------
; sum.asm
; Learning to sum 2 numbers with 64 bit assembly
; (for GNU/Linux Assembly x80_64 Intel syntax & NASM compiler)
;
; Compile: nasm -f elf64 sum.asm
; Link: ld -s -o sum sum.o
; Run: ./sum
;
; Author: Ferran
;
; NOTE: Included here the function dec2stru(2) extracted from BASELIB(c)
; (owned by stressful - Nasm forum member)
;-------------------------------------------------------------------------
segment .data
num1: dd 654321
num2: dd 123456
res: dd 0
len_res equ $ - res
lf: db " ",10, 0
segment .bss
buffer resd 10
segment .text
global _start
_start:
mov rbx, [buffer] <---- Maybe is this the problem ?
.sum:
mov rax, [num1]
add rax, [num2]
; --- using a BASELIB(c) function ----
call dec2stru
; ------------------------------------
.show_result:
mov rax, 1
mov rdi, 1
mov rsi, res
mov rdx, len_res
syscall
.showLF:
mov rax, 1
mov rdi, 1
mov rsi, lf
mov rdx, 2
syscall
.exit:
xor edi, edi
mov rax, 60
syscall
;---------------------------
;dec2stru(2)
;Convert unsigned int to
;0-ended dec string
;---------------------------
;RBX : Buffer's address
;RAX : Integer to convert
;---------------------------
;Ret : String in buffer
;Note : Buffer must be large enough
;---------------------------
align 8
dec2stru:
push rax
push rdx
push rcx
push rsi
push rdi
cld
mov rdi,rbx
xor rsi,rsi
mov rcx,10
.more: xor rdx,rdx
div rcx
push rdx
inc rsi
test rax,rax
jnz .more
.get: pop rax
add al,30h
stosb
sub rsi,1
jnz .get
xor al,al
stosb
pop rdi
pop rsi
pop rcx
pop rdx
pop rax
ret
--- End code ---
Failed. Terminated with an "Segment fault" message.
What is the issue now?
fredericopissarra:
Your decstru funcion is pushing lots of values on stack and not poping enough.
And it is still wrong. You should pay attention to details instead of copying someone else's code.
The algorithm should be:
--- Code: ---; p = pointer to the end of buffer;
; c = counter
; q = quotient;
; r = remainder;
p = buffer + sizeofbuffer - 1;
c = 0;
do { q = n / 10; r = n % 10; n = q; *p-- = r + '0'; c++; } while ( q != 0 );
return ++p, c;
--- End code ---
A modified examlpe (with many corrections) to your code:
--- Code: ---;------------------------------------------------------------------------
; sum.asm
;
; Compile: nasm -f elf64 sum.asm -o sum.o
; ld -s -o sum sum.o
;
; It is garanteed initializing E?? portion of R?? will zero
; the upper 32 bits, so using 'mov eax,1' is *shorter* than
; 'mov rax,1' and has the same effect.
;
; Using LEA instead of MOV to load pointers is my preference.
; There is nothing wrong using MOV.
;-------------------------------------------------------------------------
section .data
; If you intend to read two QWORDs, these must be declares as QWORDs,
; not DWORDs.
num1: dq 654321
num2: dq 123456
section .rodata
lf: db `\n`
lf_len equ ($ - lf)
section .text
global _start
_start:
mov rax,[num1] ; Reading QWORDs, see?
add rax,[num2]
call printulong
mov eax,1
mov edi,eax
lea rsi,[lf]
mov edx,lf_len
syscall
mov eax,60
xor edi,edi
syscall
;---------------------------
; printulong
; Print unsigned long int in decimal.
;---------------------------
; Entry: RAX: unsigned long int to convert
; Destroys: RAX,RBX, RCX, RDX and RSI
; Unless you save and restore them.
;---------------------------
align 4
printulong:
; push rax ; Don't need to save them
; push rbx ; for this code.
; push rcx
; push rsi
; push rsi
sub rsp,32 ; Allocate space for buffer on stack.
; I could allocate only 20 bytes, but the stack
; pointer must be aligned by 8.
;
; Why 20 bytes? The maximum decimal value for
; an unsigned QWORD is "18446744073709551615".
lea rsi,[rsp+24] ; Points to the end of the buffer.
xor ecx,ecx ; counter = 0.
mov ebx,10 ; divisor.
align 4
.loop:
xor edx,edx
div rbx
add dl,'0' ; add '0' to the remainder, not the quotient!
mov [rsi],dl ; store it on the buffer.
inc ecx ; we have one more char there.
dec rsi ; points to 'next' position.
test rax,rax ; quotient == 0?
jnz .loop ; no, loop.
inc rsi ; points to the begining of the buffer.
mov eax,1 ; sys_write
mov edi,eax ; stdout
mov edx,ecx ; string size.
syscall
add rsp,32 ; Reclaim allocated space.
; pop rsi ; Don't need to restore them
; pop rdx ; for this code.
; pop rcx
; pop rbx
; pop rax
ret
--- End code ---
Ferran:
OK @federicopissarra I understand the algorithmic process for to converse a binary to decimal number, and after make an string with it. This idea is entered in my head. My little problem is how to codify this.
Now, I'm going to study your code and i'll come back soon. Thank you for all.
Ferran:
@federicopissarra
here i go again. I tested the code, it works perfectly :)
Only I needed to adapt the code to my project of a modular way (the printing is out of function), but the rest is the same. This already allows me to add a whole series of arithmetic functions of unsigned integers and they can be printed every time it is requested.
The code now is this:
--- Code: ---;------------------------------------------------------------------------
; sum.asm
;
; Compile: nasm -f elf64 sum.asm -o sum.o
; ld -s -o sum sum.o
;
; It is garanteed initializing E?? portion of R?? will zero
; the upper 32 bits, so using 'mov eax,1' is *shorter* than
; 'mov rax,1' and has the same effect.
;
; Using LEA instead of MOV to load pointers is my preference.
; There is nothing wrong using MOV.
;-------------------------------------------------------------------------
section .data
num1: dq 654321 ;
num2: dq 123456
lres: db 0
section .rodata
lf: db `\n`
lf_len equ ($ - lf)
section .bss
res: resb 8
section .text
global _start
_start:
; --- token sum res = (num1 + num2) --------------
mov rax,[num1] ; number 1
add rax,[num2] ; number 2
call printulong ; conversion to dec
mov [res], rsi ; result of the sum
mov [lres], ecx ; length of result
; ----------- token show (res) -------------------
mov eax,1 ; sys_write
mov edi,eax ; stdout
mov rsi, [res] ; string to display
mov edx, [lres] ; string size.
syscall
; ----------token show (lf) ----------------------
mov eax,1
mov edi,eax
lea rsi,[lf]
mov edx,lf_len
syscall
; -----------token exit --------------------------
mov eax,60
xor edi,edi
syscall
;---------------------------
; printulong
; Print unsigned long int in decimal.
;---------------------------
; Entry: RAX: unsigned long int to convert
; Destroys: RAX,RBX, RCX, RDX and RSI
; Unless you save and restore them.
;---------------------------
align 4
printulong:
sub rsp,32 ; Allocate space for buffer on stack.
lea rsi,[rsp+24] ; Points to the end of the buffer.
xor ecx,ecx ; counter = 0.
mov ebx,10 ; divisor.
.loop:
xor edx,edx
div rbx
add dl,'0' ; add '0' to the remainder, not the quotient!
mov [rsi],dl ; store it on the buffer.
inc ecx ; we have one more char there.
dec rsi ; points to 'next' position.
test rax,rax ; quotient == 0?
jnz .loop ; no, loop.
inc rsi ; points to the begining of the buffer.
add rsp,32 ; Reclaim allocated space.
ret
--- End code ---
NOTE: As if, ithe code works well when num1 is positive and num2 is negative, making the substraction :)
In other hand I will be able to adapt this program easily when I would load values into variables by arguments, arrays, lists, functions or file data.
Now i need to do the same with unsigned and floating point numbers, but this is another history...
Navigation
[0] Message Index
[#] Next page
[*] Previous page
Go to full version