Mips Assembly. Connect, read, and write - sockets

My objective is to open a socket, connect to that socket on a port, and then whenever that socket sends data to me, I want to write it to stdout.
My code works fine, but for some reason the string that is writing doesn't null terminate? I'm not so sure what the issue is and I have yet to find anything online about it.
#socket(2,1,0)
li $t7, -6
nor $t7, $t7, $zero
addi $a0, $t7, -3
addi $a1, $t7, -3
slti $a2, $zero, -1
li $v0, 4183
syscall 0x40404
sw $v0, -4($sp)
#connect(3, &addr, 16)
lw $a0, -4($sp)
li $t7, -3
nor $t7, $t7, $zero
sw $t7,-32($sp)
lui $t6,0x7a69
ori $t6,$t6,0x7a69
sw $t6, -28($sp)
lui $t5, 0x7F00
ori $t5, $t5, 0x1
sw $t5, -26($sp)
addiu $a1, $sp, -30
li $t4, -17
nor $a2, $t4, $zero
li $v0, 4170
syscall 0x40404
#read(3, addr, 50)
nex:
lw $a0, -4($sp)
addiu $a1, $sp,-64
li $a2, 50
addi $a2, $a2, -1
li $v0, 4003
syscall 0x40404
beqz $a3, next
move $a2,$v0
negu $a2,$v0
next:
blez $a2,nextt
#write(1, addr, 50)
li $a0, 1
li $v0, 4004
syscall 0x40404
j nex
nextt:
Here is the strace of me writing a\n to the socket, and it writing a\n\0\0\0\0\0\0\0\0 to stdout.
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(31337), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
read(3, "a\n", 49) = 2
write(1, "a\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 49a
zi3▒ݤ) = 49
As you can see, it prints out some weird characters at the end. Thanks for any help!

Notice in your strace output that your read syscall returns a value of 2 [in $v0].
Also notice that your write syscall has a length much greater than 2.
After your read syscall you have:
move $a2,$v0 # this reg has 2
negu $a2,$v0 # BUG: this changes it to -2 (0xFFFFFFFE)
The length for the write was interpreted as an unsigned number [and a very large one]
Change this to just [i.e. remove the negu]:
move $a2,$v0

Related

How to get source IP address of a UDP packet using recvfrom in nasm?

I'm writing a UDP socket in nasm and I'm using the recvfrom system call to receive a UDP packet from a client.
I can successfully get the message sent, but I would like to send back to the client an answer.
The problem is that I can't extract the source IP address of the packet, so I can't use the sendto system call.
This is the code of the UDP server:
%include "../StandardLibrary/standardlib.inc"
%include "./network.inc"
PORT_NUMBER equ 4096
%macro printError 3
print %1
printLineInt %2, %3
%endmacro
%macro clearBuffer 1
getLength %1
mov r12, 0
%%loop:
mov [%1 + r12], byte 0
inc r12
cmp r11, r12
jne %%loop
%endmacro
section .data
sock_addr:
istruc sockaddr_in
at sockaddr_in.sin_family, dw AF_INET
at sockaddr_in.sin_port, dw htons(PORT_NUMBER)
at sockaddr_in.in_addr, db 00h, 00h, 00h, 00h
at sockaddr_in.sin_zero, db 0, 0, 0, 0, 0, 0, 0, 0
iend
client_sockaddr:
istruc sockaddr
at sockaddr.sa_family, dw AF_INET
at sockaddr.sa_data, db 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0, 0
iend
;Messaggi di successo
so_creation_success db "Socket creato con successo", 0
so_binding_success db "Binding del socket eseguito con successo", 0
so_started_capturing db "Socket in ascolto di messaggi...", 0
;Messaggi di errore
so_creation_error db "Errore nella creazione del socket: ", 0
so_binding_error db "Errore nel binding del socket: ", 0
so_capture_error db "Errore nella ricezione del messaggio: ", 0
so_sending_error db "Errore nell'invio del messaggio: ", 0
section .bss
buffer resb 100
socket_fd resw 1
error_code resq 1
tmp resb 10
section .text
global _start
_start:
;1) Creazione del socket
mov rax, SYS_SOCKET
mov rdi, AF_INET
mov rsi, SOCK_DGRAM
mov rdx, 0
syscall
cmp rax, -1
jle _socket_error
;Carica nello stack il file descriptor
mov [socket_fd], rax
printLine so_creation_success
;2) Binding del socket
mov rax, SYS_BIND
mov rdi, [socket_fd]
mov rsi, sock_addr
mov rdx, sockaddr_in_size
syscall
cmp rax, -1
jle _binding_error
printLine so_binding_success
;3) Ricezione dei messaggi
_listen:
mov rax, SYS_RECVFROM
mov rdi, [socket_fd]
mov rsi, buffer
mov rdx, 20
mov r10, 0
mov r8, client_sockaddr
mov r9, 16
syscall
cmp rax, -1 ;Controlla che non ci siano stati errori
jle _capture_error
cmp rax, 1 ;Controlla che non sia stato ricevuto un pcchetto vuoto
jle _exit ;è definito vuoto anche un pacchetto con un solo carattere
;Messaggio ricevuto con successo
print buffer
clearBuffer buffer ;Svuota il buffer
jmp _listen
;Il programma è terminato con successo
_exit:
exit
;Errore nella creazione del socket
_socket_error:
neg rax
mov [error_code], rax
printError so_creation_error, [error_code], tmp
exit [error_code]
;Errore durante il binding del socket
_binding_error:
neg rax
mov [error_code], rax
printError so_binding_error, [error_code], tmp
exit [error_code]
;Errore durante la ricezione del messaggio
_capture_error:
neg rax
mov [error_code], rax
printError so_capture_error, [error_code], tmp
exit [error_code]
And on network.inc I have:
SYS_SOCKET equ 41 ;Id system call per la creazione del socket
SYS_SENDTO equ 44 ;Id system call per l'invio di datagram UDP
SYS_RECVFROM equ 45 ;Id system call per la ricezione di datagram UDP
SYS_BIND equ 49 ;Id system call per legare un socket ad un indirizzo IP (o ad una famiglia)
AF_INET equ 2 ;Rete IPv4
SOCK_DGRAM equ 2 ;Id del protocollo UDP
INADDR_ANY equ 0 ;Indica che il socket accetta comunicazioni da qualsiasi indirizzo IP
;Traduce x in un valore di tipo network byte order
%define htons(x) ((x >> 8) & 0xFF) | ((x & 0xFF) << 8)
;Rappresenta un indirizzo IPv4
struc in_addr
.s_addr: resb 4 ;Valore dei 4 ottetti
endstruc
;Rappresenta la struttura di un socket
struc sockaddr_in
.sin_family: resw 1 ;Id del tipo di indirizzo
.sin_port: resw 1 ;Numero di porta
.in_addr: resb 4 ;Indirizzo IP
.sin_zero: resb 8 ;Byte di rimepimento
endstruc
struc sockaddr
.sa_family resw 1
.sa_data resb 14
endstruc
As UDP client I'm using the netcat command: netcat -u 127.0.0.1 4096
You can pass a pointer to your sockaddr structure in SYS_RECVFROM according to the documentation here:
mov r8, 0
mov r9, 0
And then use filled structure with sendto syscall.
UPD
sockaddr has following shape in C:
struct sockaddr {
unsigned short int sa_family;
char sa_data[14];
};
I think, it looks something like this in NASM:
struc sockaddr
.sa_family resw 1
.sa_data db 14
endstruc
client_sock_addr:
istruc sockaddr
at sockaddr.sa_family, dw AF_INET
at sockaddr.sa_data, db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
iend
UPD #2
I've noticed that you're allocating 2 bytes for the socket. Actually, sockets must be int:
socket_fd resd 1
Next thing: you have to pass to r9 reference rather than value
section .data
; ...
client_sockaddr_len dd 16
; ...
; ...
mov rax, SYS_RECVFROM
mov rdi, [socket_fd]
mov rsi, buffer
mov rdx, 20
mov r10, 0
mov r8, client_sockaddr
mov r9, client_sockaddr_len
syscall
And finally you can sendto
mov rax, SYS_SENDTO
mov rdi, [socket_fd]
mov rsi, buffer
mov rdx, 50
mov r10, 0
mov r8, client_sockaddr
mov r9, [client_sockaddr_len]
syscall

MIPS Assembly convert integer to ascii string using memory

Hi i have a problem with my subroutine code. here is my code. It's giving a
Runtime exception at 0x00400074: address out of range 0x000000c8 error.
The line is: sb $t2, 0($t4) - It's the second store byte.
intToa: addi $sp, $sp, -12
sw $ra ,8($sp)
sw $a0, 4($sp)
sw $a1, 0($sp)
move $t0, $a0
move $t4, $a1
bne $t0, $zero, while
li $t2, 48
sb $t2, 0($t4)
addi $t4, $t4, 1
b end
while: beq $t0, $zero, end
li $t6, 10
div $t0, $t6 # divide $t0 by 10
mfhi $t1 # $t3 = $t0%10 (last digit of $t0)
mflo $t0 # $t0 = $t0/10 (first digit of $t0)
addi $t2, $t1, 48 # store character '0' to $t1 in
sb $t2, 0($t4) # out destinationg string
addi $t4, $t4, 1 # increment our string pointer
j while # continue looping
end:
sb $zero, 0($t4) # null terminate our string
move $a1, $a0
jal reverse
lw $ra, 12($sp)
addiu $sp, $sp, 12 # put stack back in place
jr $ra

beq command not jumping to a label in MIPS

I am creating a MIPS code in MARS that allows only an input of a numerical expression, and print an error message when characters other than numbers, +,-,*, and / are present.
In my following code, I set $s0 to zero if there is an invalid character, otherwise it stays at 1. If it is equal to zero, using the beq command I would jump to "erroneous" which handles the error message.
However, that last part does not seem to happen. If you run my code you'll see that it actually gets the proper values of $s0 right (that is, if the expression is invalid, it becomes equal to 0).
I need a fresh set of eyes, I would appreciate any help. Thanks!
.data
input: .space 102
trial: .asciiz "LOLLOL\n"
errormsg: .asciiz "ERROR\n"
.text
main:
addi $v0, $zero, 8
la $a0, input
addi $a1, $a0, 102
syscall
addi $t1 , $zero, 0
add $s1, $zero, $zero
addi $a0, $zero, -1
addi $s0, $zero,1
check_invalid_char_1:
#beq $s0, $s1, erroneous
jal check_invalid_char
j allowed
check_invalid_char:
addi $sp,$sp,-8
sw $ra, 0($sp)
sw $a0, 4($sp)
#sw $v0, 8($sp)
addi $a0, $a0,1
addi $t3, $zero,0
beq $s0, $zero, erroneous
lb $t2, input($a0)
beq $t2, 48, check_invalid_char_1 #pwede 0
beq $t2, 49, check_invalid_char_1 #pwede 1
beq $t2, 50, check_invalid_char_1 #pwede 2
beq $t2, 51, check_invalid_char_1 #pwede 3
beq $t2, 52, check_invalid_char_1 #pwede 4
beq $t2, 53, check_invalid_char_1 #pwede 5
beq $t2, 54, check_invalid_char_1 #pwede 6
beq $t2, 55, check_invalid_char_1 #pwede 7
beq $t2, 56, check_invalid_char_1 #pwede 8
beq $t2, 57, check_invalid_char_1 #pwede 9
beq $t2, 43, check_invalid_char_1 #pwede +
beq $t2, 45, check_invalid_char_1 #pwede -
beq $t2, 42, check_invalid_char_1 #pwede *
beq $t2, 47, check_invalid_char_1 #pwede /
beq $t2, 0, allowed #pwede null terminator
beq $t2, 10, allowed #pwede newline
add $s0, $zero,$zero
lw $ra, 0($sp)
lw $a0, 4($sp)
#lw $v0, 8($sp)
addi $sp, $sp, 8
jr $ra
erroneous:
#add $a0, $zero, $zero
la $a0, errormsg
addi $v0, $zero, 4
syscall
allowed:
addi $v0, $zero, 1
add $a0, $s0, $zero
syscall
#la $a0, errormsg
#addi $v0, $zero, 4
#syscall
addi $v0, $zero, 10
syscall
To anyone who may encounter this question, I may have solved my own problem, but I am not sure if it is really a fix, or a "cheat". It's more of a work around really.
I moved the "beq $s0, $zero, erroneous" line to the "allowed:" label. I don't know why it doesn't work from inside check_valid_char, but it works.
Then inside erroneous, I reset $s0 to 0 by using "sub $s0, $s0, $s0" so that when the code goes again to allowed: , beq will just be skipped and it will end normally.
If others can find a "real" solution for my problem, please post that.
Thanks!
edit: some punctuations.

MIPS float printing

I wrote this code in MIPS to calculate the sum of N-numbers with double float precision.
But when I print the result it prints 0.00000 althought I see that in memory it's the correct result.
Anyone can help me with this?
#architecture ex.2
.data
first: .asciiz "Give the number of the summation"
m1: .asciiz "Give the"
m2: .asciiz "th number."
nl: .asciiz "\n"
final: .asciiz "The sum is"
.text
main:
li $v0, 4
la $a0, first
syscall
li $v0,5
syscall
move $t1,$v0
li $v0, 4
la $a0, nl
syscall
li $t2,0
li $t0,1
mtc1.d $t2, $f2
cvt.d.w $f2, $f2
Sumin:
li $t3,0
li $v0, 4
la $a0, m1
syscall
li $v0,1
move $a0,$t0
syscall
li $v0, 4
la $a0, m2
syscall
li $v0, 4
la $a0, nl
syscall
li $v0,5
syscall
move $t3,$v0
mtc1.d $t3, $f14
cvt.d.w $f14, $f14
add.d $f2,$f2,$f14
addi $t0,$t0,1
ble $t0,$t1,Sumin
Sumexit:
li $v0, 4
la $a0, final
syscall
li $v0, 4
la $a0, nl
syscall
li $v0,2
mov.d $f12,$f2
syscall
END:jr $ra
I'd just suggest printing the double in $f12, not just the float
li $v0, 3
mov.d $f12, $f2
syscall

MIPS - IEEE binary64 (double) and signed integer multiplication

I have a problem with MIPS project. The task is to multiply binary64(double) number by a signed integer without using floating-point Unit. It is almost working well, but for some numbers an error occurs(ex. float-123456789123456, int - 1). By error I mean that after 7th digit my result seems to differ from the proper one. I suspect there can be a problem with transfer of some bit during the procedure(maybe in process of adding $high of mantissa2 and $low of mantissa2). I tried to correct it, but so far I have no idea how to do it. Please verify my code and correct it if possible.
.data
text1: .asciiz "Enter double: "
text2: .asciiz "Enter integer: "
text3: .asciiz "Result: "
quest: .asciiz "\nIf you want to multiply enter 1, otherwise enter 0: "
num1a: .word 0 #multiplicand and result(sign exponent and first part of mantissa)
num1b: .word 0 #second part of the multiplicand and result(remaining part of mantissa)
num2: .word 0 #integer
.text
.globl input
input:
#print "Enter double: "
la $a0, text1
li $v0, 4
syscall
# saving input double into num1
li $v0, 7
syscall
swc1 $f0, num1b
swc1 $f1, num1a
#print "Enter integer: "
la $a0, text2
li $v0, 4
syscall
# saving input int into num2
li $v0, 5
syscall
sw $v0, num2
# loading data to registers
lw $t0, num1a
lw $t1, num1b
lw $t2, num2
#########################################################sign
sign:
move $t3, $t0
andi $t3, $t3, 0x80000000 #preserve sign, zero the rest
bgez $t2, extract #if less than zero we change the final sign and negate the value of integer
xori $t3, $t3, 0x80000000 #multiply signs (if integer is negative, then the sign is equal to $s0)
neg $t2, $t2 #absolute value of int
extract:
################################################checking for zero
or $t5, $t0, $t1 #if both part of double are equal to zero we skip all the calculation
beqz $t5, result_zero
beqz $t2, result_zero
###############################sign, exponent and mantissa
move $t7, $t0
andi $t7, $t7, 0x7FF00000 #extracting exponent to $t7
move $t8, $t0
andi $t8, $t8, 0x000FFFFF #extracting first part of mantissa
ori $t8, $t8, 0x00100000 #adding prefix one to mantissa
#remaining mantissa stays in register $t1
#########################################################
multiply:
########################multiplying mantissa part 1
multu $t8, $t2 #multiply mantissa1 by integer
mflo $t8 #low part of multiplication to $t8
mfhi $s1 #high part of multiplication to $s1
########################multiplying mantissa part 2
multu $t1, $t2 #mantissa part 2 multiplication
mflo $t1 #low part to $t1
mfhi $t0 #with overflow going to $t0
########################partial accumulation
addu $t8, $t8, $t0 #adding the high part of mantissa2 to result of low part of mantissa1
bgeu $t8, $t0, skip_add #if the result is less than any element we add 1 to mantissa1 high
addiu $s1, $s1, 1
######
skip_add:
bnez $s1, shift
bltu $t8, 0x00200000, result
shift: #else we shift 3 parts of mantissa and increment the the exponent
###extracting least significant bit of high mantissa1
sll $s2, $s1, 31 #copying least significant beat of $s1 to most significant bit in $s2
sll $t9, $t8, 31 #copying least significant beat of $s8 to most significant bit in $t9
######
srl $s1, $s1, 1 #shifting right mantisa part1 high
srl $t8, $t8, 1 #shifting right mantisa part1 low
or $t8, $t8, $s2 #copying least significant bit from mantissa1- high to most significant bit of mantissa1 low
srl $t1, $t1, 1 #shifting right mantisa part2
or $t1, $t1, $t9 #copying least significant bit from mantissa1 to most significant bit of mantissa2
######
addiu $t7, $t7, 0x00100000 #increment exponent by one
######
bnez $s1, shift #if mantissa1 high is greater than zero we continue
bgeu $t8, 0x00200000, shift #if mantissa1 low exceeds final mantissa space
result:
andi $t8, $t8, 0x000FFFFF #preserve mantissa, zero the rest(cut the prefix - one)
move $t0, $t3 #copy propoer sign
or $t0, $t0, $t7 #add exponent
or $t0, $t0, $t8 #add mantissa part1
b output
result_zero:
li $t0, 0
li $t1, 0
output:
sw $t0, num1a
sw $t1, num1b
#print "Result: "
la $a0, text3
li $v0, 4
syscall
lwc1 $f12, num1b
lwc1 $f13, num1a
#print double - the result
li $v0, 3
syscall
question:
la $a0, quest #Do you want to enter new numbers or finish?
li $v0, 4
syscall
li $v0, 5 #reads the answer (integer)
syscall
beq $v0, 1, input #if input =1, continue, if 0 finish, otherwise ask again
beqz $v0, fin
b question
fin:
li $v0, 10 #exit
syscall
I think the problem might be in this section(multiply):
addu $t8, $t8, $t0 #adding the high part of mantissa2 to result of low part of mantissa1
bgeu $t8, $t0, skip_add #if the result is less than any element we add 1 to mantissa1 high
#addiu $s1, $s1, 1
######
skip_add:
bnez $s1, shift
bltu $t8, 0x00200000, result
The process of adding may cause a carry out. I tried to handle it with instruction held in comment (addiu).It means that if the result of adding two unsigned numbers is less than one of them we obtain a cary out and have to add 1 to register $s1 which holds the most significant part of mantissa.It didn't help.
In my opinion this is the correct code:
.data
text1: .asciiz "Enter double: "
text2: .asciiz "Enter integer: "
text3: .asciiz "Result: "
quest: .asciiz "\nIf you want to multiply enter 1, otherwise enter 0: "
num1a: .word 0 #multiplicand and result(sign exponent and first part of mantissa)
num1b: .word 0 #second part of the multiplicand and result(remaining part of mantissa)
num2: .word 0 #integer
.text
.globl input
input:
#print "Enter double: "
la $a0, text1
li $v0, 4
syscall
# saving input double into num1
li $v0, 7
syscall
swc1 $f0, num1b
swc1 $f1, num1a
#print "Enter integer: "
la $a0, text2
li $v0, 4
syscall
# saving input int into num2
li $v0, 5
syscall
sw $v0, num2
# loading data to registers
lw $t0, num1a
lw $t1, num1b
lw $t2, num2
#########################################################sign
sign:
move $t3, $t0
andi $t3, $t3, 0x80000000 #preserve sign, zero the rest
bgez $t2, extract #if less than zero we change the final sign and negate the value of integer
xori $t3, $t3, 0x80000000 #multiply signs (if integer is negative, then the sign is equal to $s0)
neg $t2, $t2 #absolute value of int
extract:
################################################checking for zero
or $t5, $t0, $t1 #if both part of double are equal to zero we skip all the calculation
beqz $t5, result_zero
beqz $t2, result_zero
###############################sign, exponent and mantissa
move $t7, $t0
andi $t7, $t7, 0x7FF00000 #extracting exponent to $t7
move $t8, $t0
andi $t8, $t8, 0x000FFFFF #extracting first part of mantissa
ori $t8, $t8, 0x00100000 #adding prefix one to mantissa
#remaining mantissa stays in register $t1
#########################################################
multiply:
########################multiplying mantissa part 1
multu $t8, $t2 #multiply mantissa1 by integer
mflo $t8 #low part of multiplication to $t8
mfhi $s1 #high part of multiplication to $s1
########################multiplying mantissa part 2
multu $t1, $t2 #mantissa part 2 multiplication
mflo $t1 #low part to $t1
mfhi $t0 #with overflow going to $t0
########################partial accumulation
addu $t8, $t8, $t0 #adding the high part of mantissa2 to result of low part of mantissa1
bgeu $t8, $t0, skip_add #if the result is less than any element we add 1 to mantissa1 high
addiu $s1, $s1, 1
######
skip_add:
bnez $s1, shift
bltu $t8, 0x00200000, result
shift: #else we shift 3 parts of mantissa and increment the the exponent
###extracting least significant bit of high mantissa1
sll $s2, $s1, 31 #copying least significant beat of $s1 to most significant bit in $s2
sll $t9, $t8, 31 #copying least significant beat of $s8 to most significant bit in $t9
######
srl $s1, $s1, 1 #shifting right mantisa part1 high
srl $t8, $t8, 1 #shifting right mantisa part1 low
or $t8, $t8, $s2 #copying least significant bit from mantissa1- high to most significant bit of mantissa1 low
srl $t1, $t1, 1 #shifting right mantisa part2
or $t1, $t1, $t9 #copying least significant bit from mantissa1 to most significant bit of mantissa2
######
addiu $t7, $t7, 0x00100000 #increment exponent by one
######
bnez $s1, shift #if mantissa1 high is greater than zero we continue
bgeu $t8, 0x00200000, shift #if mantissa1 low exceeds final mantissa space
result:
andi $t8, $t8, 0x000FFFFF #preserve mantissa, zero the rest(cut the prefix - one)
move $t0, $t3 #copy propoer sign
or $t0, $t0, $t7 #add exponent
or $t0, $t0, $t8 #add mantissa part1
b output
result_zero:
li $t0, 0
li $t1, 0
output:
sw $t0, num1a
sw $t1, num1b
#print "Result: "
la $a0, text3
li $v0, 4
syscall
lwc1 $f12, num1b
lwc1 $f13, num1a
#print double - the result
li $v0, 3
syscall
question:
la $a0, quest #Do you want to enter new numbers or finish?
li $v0, 4
syscall
li $v0, 5 #reads the answer (integer)
syscall
beq $v0, 1, input #if input =1, continue, if 0 finish, otherwise ask again
beqz $v0, fin
b question
fin:
li $v0, 10 #exit
syscall