Incorrect console output after previous output - linux

Task: output the number in hexadecimal form to the console. After that print some string (let it be "String after num").
The first part is successful, but the second is not.
The input number is stored in memory by the num label.
String is stored in memory by the line label.
String length - lines.
Code:
global _start
section .data
num db 01111110b
temp db 0
line db 10, "String after num", 10
lines equ $-line
section .text
_start:
call write_hex ; write num in hex format
mov eax, 4 ; write "Hello world!"
mov ebx, 1 ;
mov ecx, line ;
mov edx, lines ;
int 80H ;
mov eax, 1 ; exit
xor ebx, ebx
int 80H
write_hex:
mov eax, [num]
mov [temp], eax
shr byte [num], 4
call to_hex_digit
call write_digit
mov eax, [temp]
mov [num], eax
and byte [num], 1111b
call to_hex_digit
call write_digit
ret
to_hex_digit:
add [num], byte '0'
cmp [num], byte '9'
jle end
add [num], byte 7
end: ret
write_digit:
mov eax, 4
mov ebx, 1
mov ecx, num
mov edx, 1
int 80H
ret
Output:
Thanks for any help.

I used an invalid register to store a temporary value. I replaced the register which will work with the temp from eax to al. See Jester's answer.

Related

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

Copy a string to another variable x86 Assembly

I would like to make a copy of a string and store the copy in another variable. I want to do it the most basic way, cause I have just started learning Assembly.
I have something like this:
section .data
mystring db "string goes here", 10 ;string
mystringlen equ $- mystring ;length
helper dw 0 ;variable to help me in a loop
Now, I thought of a loop that will take each byte of the string and assign it to new string.
I have this (I know it only changes initial string, but doesn't work either):
loopex:
mov [mystring+helper], byte 'n' ;change byte of string to 'n'
add helper, 1 ;helper+=1
cmp helper,mystringlen ;compare helper with lenght of string
jl loopex
;when loop is done
mov eax, 4
mov ecx, mystring ; print changed string
mov edx, mystringlen ; number of bytes to write
;after printing
int 0x80 ; perform system call
mov eax, 1 ; sys_exit system call
mov ebx, 0 ;exit status 0
int 0x80
So I would need something like:
old_string = 'old_string'
new_string = ''
counter=0
while(counter!=len(old_string)):
new_string[counter] = old_string[counter]
counter+=1
print(new_string)
The code after help I received:
section .data
mystring db "This is the string we are looking for", 10
mystringlen equ $- mystring
section .bss
new_string: resb mystringlen
section .text
global _start
_start:
mov ecx, 0
mov esi, mystring
mov edi, new_string
loopex: ; do {
mov byte al, [esi]
mov byte [edi], al
inc esi
inc edi
inc ecx
cmp ecx, mystringlen
jl loopex ; }while(++ecx < mystringlen)
;when loop is done
mov eax, 4 ; __NR_write (asm/unistd_32.h)
mov ebx, 1 ; fd = STDOUT_FILENO
mov ecx, new_string ; bytes to write
mov edx, mystringlen ; number of bytes to write
int 0x80 ; perform system call: write(1, new_string, mystringlen)
;after printing
mov eax, 1 ; sys_exit system call number
mov ebx, 0 ; exit status 0
int 0x80

Converting user input to all caps in assembly (NASM) [duplicate]

This question already has answers here:
X86 NASM Assembly converting lower to upper and upper to lowercase characters
(5 answers)
X86 Assembly Converting lower-case to uppercase
(1 answer)
Closed 3 years ago.
I want to change the string to all caps, although I am having trouble getting the length of the input. What i have tried so far is moving the address of the message into a registrar then indexing through the string and also increment a counter variable. Then comparing the char in the address to a '.' (signifying the end of the message) and if its found not to be equal it will recall this block of statements. At least this is what I want my code to do. Not sure if this is even the right logic. I know there are alot of errors and its messy but I'm learning so please just focus on my main question. thank you! EDIT: the input i use is 'this is a TEST.'
;nasm 2.11.08
SYS_Write equ 4
SYS_Read equ 3
STDIN equ 0
STDOUT equ 1
section .bss
message resb 15
counter resb 2
section .data
msg1: db 'Enter input (with a period) that I will turn into all capitals!',0xa ;msg for input
len1 equ $- msg1
section .text
global _start
_start:
mov eax, SYS_Write ; The system call for write (sys_write)
mov ebx, STDOUT ; File descriptor 1 - standard output
mov ecx, msg1 ; msg to print
mov edx, len1 ; len of message
int 0x80 ; Call the kernel
mov eax, SYS_Read ;system call to read input
mov ebx, STDIN ;file descriptor
mov ecx, message ;variable for input
mov edx, 15 ;size of message
int 0x80 ;kernel call
mov [counter], byte '0'
getLen:
mov eax, message
add eax, [counter]
inc byte [counter]
cmp eax, '.'
jne getLen
mov eax, SYS_Write ; this is to print the counter to make sure it got the right len
mov ebx, STDOUT
mov ecx, counter
mov edx, 2
int 0x80
jmp end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov eax, [message]
;add eax, counter
cmp eax, 90
jg toUpper
toUpper:
sub eax, 32
mov [message], eax
mov eax, SYS_Write ; The system call for write (sys_write)
mov ebx, STDOUT ; File descriptor 1 - standard output
mov ecx, message ; Put the offset of hello in ecx
mov edx, 10 ; helloLen is a constant, so we don't need to say
int 0x80 ; Call the kernel
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
end:
mov eax,1 ; The system call for exit (sys_exit)
mov ebx,0 ; Exit with return code of 0 (no error)
int 0x80 ;

Getting digit instead of Ascii in nasm assembly intel x86

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

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