Getting digit instead of Ascii in nasm assembly intel x86 - linux

I'm trying to learn the basics of assembly but can't get across on how to display results stored in memory.
section .data
num1 db 1,2,3,4,5
num2 db 1,2,3,4,5
output: db 'The dot product is "'
outputLen1 : equ $-output
output2: db '" in Hex!', 10
output2Len : equ $-output2
section .bss
dotProd resw 1 ; store dot product in here
section .text
global _start
_start:
mov eax, 0
mov ecx, 5
mov edi, 0
mov esi, 0
looper: mov ax, [edi + num1]
mov dx, [esi + num2]
mul dx
add [dotProd], ax
cmp cx, 1
je printOutput
inc edi
inc esi
dec cx
jmp looper ; go back to looper
printOutput:
mov eax,4 ; The system call for write (sys_write)
mov ebx,1 ; File descriptor 1 - standard output
mov ecx, output ;
mov edx, outputLen1 ;
int 80h ; Call the kernel
mov eax, 4
mov ebx, 1
mov ecx, dotProd,
mov edx, 1
int 80h
mov eax, 4
mov ebx, 1
mov ecx, output2,
mov edx, output2Len
int 80h
jmp done
done:
mov eax,1 ; The system call for exit (sys_exit)
mov ebx,0 ; Exit with return code of 0 (no error)
int 80h
What I'm trying to do is get the dot product of the two list of numbers and display it on the screen. However, I keep getting random letters which I believe are hex representations of the real decimal value. How can I convert it to decimal? The current value display is 7, which should is the equivalent ASCII char for 55, which in this case is the dot product of both list of numbers.

esi and edi must be increased such that it points to next element of array.(in this particular example, only one of them is sufficient).
declare mun1 andnum2 as dd, instead of db (see here).
Also, you have to have method for printing number.(see this and this).
Below is a complete code which uses printf.
;file_name:test.asm
;assemble and link with:
;nasm -f elf test.asm && gcc -m32 -o test test.o
extern printf
%macro push_reg 0
push eax
push ebx
push ecx
push edx
%endmacro
%macro pop_reg 0
pop edx
pop ecx
pop ebx
pop eax
%endmacro
section .data
num1: dd 1,2,3,4,5
num2: dd 1,2,3,4,5
msg: db "Dot product is %d",10,0
section .bss
dotProd resd 1 ; store dot product in here
section .text
global main
main:
mov eax, 0
mov ecx, 5
mov edx, 0
mov esi, 0
mov dword[dotProd], 0h
looper: mov eax, dword[esi + num1]
mov edx, dword[esi + num2]
mul edx
add [dotProd], eax
cmp cx, 1
je printOutput
add esi,4
dec cx
jmp looper ; go back to looper
printOutput:
push_reg
push dword[dotProd]
push dword msg
call printf
add esp,8
pop_reg
jmp done
done:
mov eax,1 ; The system call for exit (sys_exit)
mov ebx,0 ; Exit with return code of 0 (no error)
int 80h

Related

Learning assembly. how to make code faster

I started to learn assembly some days ago and i write my first ever piece of code using user input, string functions, passing arguments by stack or by register etc...
I have some questions. Do you have some advices to make my code faster. For example, in my atoi function, i know that imul is time consuming. Maybe, there are enormous mistakes but as far as i know, many things to improve for sure. So my main question is : are there fatal errors in this first code and my second is : any type to refactoring code with faster instructions
SYS_READ equ 3
SYS_WRITE equ 4
STDIN equ 0
STDOUT equ 1
%macro printm 2
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, %1
mov edx, %2
int 0x80
%endmacro
%macro prolog 0
push ebp,
mov ebp, esp
%endmacro
%macro epilog 0
mov esp, ebp
pop ebp
%endmacro
section .text
global _start
_start:
; first check if our strlen proc works
push dword msgbegin
call strlen
add esp, byte 4
cmp eax, lenbegin
je .suite ; it works, we continue
; exiting prog if the len computed in rax != lenbegin
mov eax, 1
int 0x80
.suite:
; check if strcpy works printing res (msgbegin -> srcdst)
push dword lenbegin
push dword msgbegin
push dword strdst
call strcpy
add esp, byte 12
push dword lenbegin
push dword strdst
call print
add esp, byte 8
; first input
printm msgbinp1, leninp1
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num1
mov edx, 2
int 0x80
printm msgbinp2, leninp2
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, num2
mov edx, 2
int 0x80
printm msgbinp3, leninp3
mov eax, SYS_READ
mov ebx, STDIN
mov ecx, bignum
mov edx, 4
int 0x80
mov edx, bignum
call atoi
cmp eax, 123
je .success ; exit if bignum != 123
mov eax, 1
int 0x80
.success:
; need to strip line feed from bignum
printm bignum, 4
printm msgoutp, lenoutp
; now we compute the sum
mov eax, [num1]
sub eax, '0'
mov ebx, [num2]
sub ebx, '0'
add eax, ebx
add eax, '0'
mov [sum], eax
printm msgres, lenres
; we print it
printm sum, 1
; exiting the programm
mov eax, 1
int 0x80
print:
push ebp
mov ebp, esp
mov eax, 4
mov ebx, 1
mov ecx, [ebp + 8]
mov edx, [ebp + 12]
int 0x80
mov esp, ebp
pop ebp
ret
strcpy:
push ebp
mov ebp, esp
mov ecx, [ebp + 16]
mov esi, [ebp + 12]
mov edi, [ebp + 8]
rep movsb
mov esp, ebp
pop ebp
ret
strlen:
push ebp
mov ebp, esp
push edi
push ecx
mov edi, [ebp + 8]
sub ecx, ecx
sub al, al
not ecx
cld
repne scasb
not ecx
lea eax, [ecx] ; keep null term in size
pop ecx
pop edi
mov esp, ebp
pop ebp
ret
atoi:
xor eax, eax ; zero a "result so far"
.top:
movzx ecx, byte [edx] ; get a character
inc edx ; ready for next one
cmp ecx, '0' ; valid?
jb .done
cmp ecx, '9'
ja .done
sub ecx, '0' ; "convert" character to number
imul eax, 10 ; multiply "result so far" by ten
add eax, ecx ; add in current digit
jmp .top ; until done
.done:
ret
section .data
msgbegin db "hello everyone !", 0xa, 0
lenbegin equ $ - msgbegin
msgbinp1 db "Enter a digit : ", 0xa, 0
leninp1 equ $ - msgbinp1
msgbinp2 db "Enter second digit : ", 0xa, 0
leninp2 equ $ - msgbinp2
msgbinp3 db "Enter third digit : ", 0xa, 0
leninp3 equ $ - msgbinp3
msgoutp db "is equal to 123 !", 0xa, 0
lenoutp equ $ - msgoutp
msgres db "sum of x and y is ", 0xa, 0
lenres equ $ - msgres
strdst times lenbegin db 0
segment .bss
sum resb 1
num1 resb 2
num2 resb 2
bignum resd 4
Thanks you. I started reading the doc but i'm not sure that i understood key concepts.

Printing current pid in assembly [duplicate]

I'm a novice Assembly x86 Learner, and i want to add two numbers (5+5) and print the result on the screen.
here is my code:
global _start
section .text
_start:
mov eax, 5
mov ebx, 5
add eax, ebx
push eax
mov eax, 4 ; call the write syscall
mov ebx, 1 ; STDOUT
pop ecx ; Result
mov edx, 0x1
int 0x80
; Exit
mov eax, 0x1
xor ebx, ebx
int 0x80
Correct me please
Another approach to convert an unsigned integer to a string and write it:
section .text
global _start
_start:
mov eax, 1234567890
mov ebx, 5
add eax, ebx
; Convert EAX to ASCII and store it onto the stack
sub esp, 16 ; reserve space on the stack
mov ecx, 10
mov ebx, 16
.L1:
xor edx, edx ; Don't forget it!
div ecx ; Extract the last decimal digit
or dl, 0x30 ; Convert remainder to ASCII
sub ebx, 1
mov [esp+ebx], dl ; Store remainder on the stack (reverse order)
test eax, eax ; Until there is nothing left to divide
jnz .L1
mov eax, 4 ; SYS_WRITE
lea ecx, [esp+ebx] ; Pointer to the first ASCII digit
mov edx, 16
sub edx, ebx ; Count of digits
mov ebx, 1 ; STDOUT
int 0x80 ; Call 32-bit Linux
add esp, 16 ; Restore the stack
mov eax, 1 ; SYS_EXIT
xor ebx, ebx ; Return value
int 0x80 ; Call 32-bit Linux

NASM: SegFault on MOV ECX

I'm trying to make a very simple assembly program run, however I seem to get segfaults whatever I do.
Here is my code (should print 'a' on a linux machine)
section .data
buffer times 50 db 97
pointer db 0
section .text
global _start
_start:
mov ECX , pointer
mov EDX , [buffer + ECX]
mov EAX , 4
mov EBX , 1
mov ECX , EDX
mov EDX , 1
int 0x80
It causes a segfault on the first MOV but it seems obvious to me that it should work.
I reduced it to almost nothing and it still segfault.
section .data
msg db "hello"
section .text
global _start
_start:
mov EAX,1
I've run this succesfully:
section .text
global _start
_start:
mov ax, 0b
dec ax
sub ax, 11111111b
mov bx, 97
add ax, bx
mov [INVENTORY], ax ; put a in first inventory pos
mov eax, 4
mov ebx, 1
mov ecx, INVENTORY
mov edx, 1
int 0x80
mov ax, [INVENTORY]
add ax, 1
mov [INVENTORY + 1], ax ; put b in second inventory pos
mov [VAR], ax
mov eax, 4
mov ebx, 1
mov ecx, VAR
mov edx, 1
int 0x80
mov eax, 4
mov ebx, 1
mov ecx, '\n'
mov edx, 1
int 0x80
mov eax,1
int 0x80
_newline:
section .data
VAR DW 0
INVENTORY TIMES 8 DW 0
Is it possible that it has to do with the symbols I use for newlines or tabs? I generate the assembly from java and I use \t for tabs and \n for new lines (and spaces so it doesn't look too bad.
I'm using NASM and I'm running it here:
https://www.tutorialspoint.com/compile_assembly_online.php
Thank you!
If you are just trying to print out a set of 'a's.
section .data
buffer times 50 db 97
len.buffer equ $-buffer
pointer db 0
section .text
global _start
_start:
; ssize_t write(int fd, const void *buf, size_t count);
; i386 ebx ecx edx esi edi ebp
mov EAX , 4 ; write syscall
mov EBX , 1 ; std out
lea ecx, [buffer] ; buffer
mov edx, len.buffer ; size
int 0x80
_exit:
mov eax, 1 ; exit syscall
int 0x80
output:
./yvon_001
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\ndavid#ubuntuserver00A:~/asm$ ./yvon_001
In the end #MichealPetch was right, I needed to add an EXIT syscall at the end of the code. The sample I tried still did a SEGFAULT because I was moving pointer instead of [pointer] in a registry.
Thanks for comments and answers!

Linux nasm assembly append character/s to a string

On NASM in Arch Linux, how can I append the character zero ('0') to a 32 bit variable? My reason for wanting to do this is so that I can output the number 10 by setting a single-digit input to 1 and appending a zero. I need to figure out how to append the zero.
The desirable situation:
Please enter a number: 9
10
Using this method, I want to be able to do this:
Please enter a number: 9999999
10000000
How can I do this?
Thanks in advance,
RileyH
Well, as Bo says... but I was bored. You seem resistant to doing this the easy way (convert your input to a number, add 1, and convert it back to text) so I tried it using characters. This is what I came up with. It's horrid, but "seems to work".
; enter a number and add 1 - the hard way!
; nasm -f elf32 myprog.asm
; ld -o myprog myprog.o -melf_i386
global _start
; you may have these in an ".inc" file
sys_exit equ 1
sys_read equ 3
sys_write equ 4
stdin equ 0
stdout equ 1
stderr equ 2
LF equ 10
section .data
prompt db "Enter a number - not more than 10 digits - no nondigits.", LF
prompt_size equ $ - prompt
errmsg db "Idiot human! Follow instructions next time!", LF
errmsg_size equ $ - errmsg
section .bss
buffer resb 16
fakecarry resb 1
section .text
_start:
nop
mov eax, sys_write
mov ebx, stdout
mov ecx, prompt
mov edx, prompt_size
int 80h
mov eax, sys_read
mov ebx, stdin
mov ecx, buffer + 1 ; leave a space for an extra digit in front
mov edx, 11
int 80h
cmp byte [buffer + 1 + eax - 1], LF
jz goodinput
; pesky user has tried to overflow us!
; flush the buffer, yell at him, and kick him out!
sub esp, 4 ; temporary "buffer"
flush:
mov eax, sys_read
; ebx still okay
mov ecx, esp ; buffer is on the stack
mov edx, 1
int 80h
cmp byte [ecx], LF
jnz flush
add esp, 4 ; "free" our "buffer"
jmp errexit
goodinput:
lea esi, [buffer + eax - 1] ; end of input characters
mov byte [fakecarry], 1 ; only because we want to add 1
xor edx, edx ; count length as we go
next:
; check for valid decimal digit
mov al, [esi]
cmp al, '0'
jb errexit
cmp al, '9'
ja errexit
add al, [fakecarry] ; from previous digit, or first... to add 1
mov byte [fakecarry], 0 ; reset it for next time
cmp al, '9' ; still good digit?
jna nocarry
; fake a "carry" for next digit
mov byte [fakecarry], 1
mov al, '0'
cmp esi, buffer + 1
jnz nocarry
; if first digit entered, we're done
; save last digit and add one ('1') into the space we left
mov [esi], al
inc edx
dec esi
mov byte [esi], '1'
inc edx
dec esi
jmp done
nocarry:
mov [esi], al
inc edx
dec esi
cmp esi, buffer
jnz next
done:
inc edx
inc edx
mov ecx, esi ; should be either buffer + 1, or buffer
mov ebx, stdout
mov eax, sys_write
int 80h
xor eax, eax ; claim "no error"
exit:
mov ebx, eax
mov eax, sys_exit
int 80h
errexit:
mov edx, errmsg_size
mov ecx, errmsg
mov ebx, stderr
mov eax, sys_write
int 80h
mov ebx, -1
jmp exit
;-----------------------------
Is that what you had in mind?

NASM loop over bytes

Currently I'm trying to loop over every single byte in a buffer (read from a file) and compare it to see if any of them is a whitespace, and write them to STDOUT. For some reason the program compiles and runs fine, but produces zero output.
section .data
bufsize dw 1024
section .bss
buf resb 1024
section .text
global _start
_start:
; open the file provided form cli in read mode
mov edi, 0
pop ebx
pop ebx
pop ebx
mov eax, 5
mov ecx, 0
int 80h
; write the contents in to the buffer 'buf'
mov eax, 3
mov ebx, eax
mov ecx, buf
mov edx, bufsize
int 80h
; write the value at buf+edi to STDOUT
mov eax, 4
mov ebx, 1
mov ecx, [buf+edi]
mov edx, 1
int 80h
; if not equal to whitespace, jump to the loop
cmp byte [buf+edi], 0x20
jne loop
loop:
; increment the loop counter
add edi, 1
mov eax, 4
mov ebx, 1
mov ecx, [buf+edi]
int 80h
; compare the value at buf+edi with the HEX for whitespace
cmp byte [buf+edi], 0x20
jne loop
; exit the program
mov eax, 1
mov ebx, 0
int 80h
The main problem was that I didn't given the address of bufsize ([bufsize]), also the loops had some problems.
Here's the fixed version, thanks everyone for your input.
section .data
bufsize dd 1024
section .bss
buf: resb 1024
section .text
global _start
_start:
; open the file provided form cli in read mode
mov edi, 0
pop ebx
pop ebx
pop ebx
mov eax, 5
mov ecx, 0
int 80h
; write the contents in to the buffer 'buf'
mov eax, 3
mov ebx, eax
mov ecx, buf
mov edx, [bufsize]
int 80h
; write the value at buf+edi to STDOUT
; if equal to whitespace, done
loop:
cmp byte [buf+edi], 0x20
je done
mov eax, 4
mov ebx, 1
lea ecx, [buf+edi]
mov edx, 1
int 80h
; increment the loop counter
add edi, 1
jmp loop
done:
; exit the program
mov eax, 1
mov ebx, 0
int 80h

Resources