mips program that finds how many times a character appears in a specific string - mips32

here is my code:
.text
.globl main
main:
li $t0,0 #creats address
la,$t1,str #creats addresses
lb $t2,char #reads "c"
lb $t3,($t1) #reads firs character from the string
if: beqz $t3,exit #if $t3=0 go to exit
bne $t3,$t2,next #if $t3!=$t2 go to next
addi $t0,$t0,1 # adds 1 to $t0
next: addi $t3,$t3,1 #puts next character in $t3
j if
exit:
li $v0,4
la $a0,mess
syscall
li $v0,1
move $a0,$t0
syscall
li $v0,4
la $a0,CRLF
syscall
li $v0,10
syscall
.data
str: .ascizz "aaabbccccddabceeffeeghi"
char: .ascii "c"
mess: .ascizz "Count is"
CRLF: .ascizz "\n"
i get this error:
spim: (parser) syntax error on line 25 of file /Users/Geil/Desktop/poutsa.s
str: .ascizz "aaabbccccddabceeffeeghi"

It looks like you want it to be .asciiz, not .ascizz.
.asciiz declares a string as null terminated. .ascizz is a syntax error.

Related

Hello world in NASM with LINK.EXE and WinAPI

I'm trying to get a simple Hello world program in NASM to run.
I want to print to the console without using C-Libraries, interfacing directly with WinAPI.
I am using the Visual Studio provided LINK.EXE for linking.
Here's my code so far:
section .data
message: db 'Hello world!',10 ; 'Hello world!' plus a linefeed character
messageLen: db $-message ; Length of the 'Hello world!' string
global _start
extern GetStdHandle
extern WriteConsoleW
extern ExitProcess
section .text
_start:
; DWORD bytes;
mov rbp, rsp
sub rsp, byte 8
; hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)
mov ecx, -11
call GetStdHandle
; WriteFile(hstdOut, message, length(message), &bytes, 0);
mov rcx, rax
mov rdx, message
mov r8, messageLen
lea r9, [rsp-4]
push 0
call WriteConsoleW
; ExitProcess(0)
mov rcx, 0
call ExitProcess
ret
Which I assemble and link like this:
nasm -f win64 .\ASM.ASM
link /entry:_start /nodefaultlib /subsystem:console .\ASM.obj "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.18362.0\um\x64\kernel32.lib" "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.18362.0\um\x64\user32.lib"
However when I run the resulting .exe file, I get nothing.
Some things I tried so far are
Using the decorated names (like _GetStdHandle#4), which resulted in the linker complaining about unresolved references
Not trying to print anything and calling Sleep, which resulted in the process sleeping indefinitely
Exiting with a different return code, which once again did nothing
What am I doing wrong?
EDIT: Fixed calling convention
There are three problems with your revised code. The first is:
message: db 'Hello world!',10 ; 'Hello world!' plus a linefeed character
messageLen: db $-message ; Length of the 'Hello world!' string
You defined messageLen to be a byte containing the length of the message and storing that value at the address of messageLen. You then do this:
mov r8, messageLen
That would move the address of label messageLen to r8. What you really should have done is define messageLen as an assembly time constant like this:
messageLen equ $-message ; Length of the 'Hello world!' string
The second problem is that you define the the string as a sequence of single byte characters:
message: db 'Hello world!',10 ; 'Hello world!' plus a linefeed character
There is nothing wrong with this, but to print them out you need to use the Ansi version of the function WriteConsole which is WriteConsoleA. Using WriteConsoleW printed the string as Unicode (UTF-16 on Windows 2000 and later, UTS-2 on NT4 and earlier versions of Windows).
The third problem is with regards to a mandatory 32 bytes of shadow space before the stack based parameter(s) are placed on the stack before making a function call. You also need to make sure the stack (RSP) is a 16-byte aligned value at the point of making a function call. These requirement can be found in the Microsoft 64-bit calling convention.
Code that would take this into account would look like this:
section .data
message: db 'Hello world!',10 ; 'Hello world!' plus a linefeed character
messageLen equ $-message ; Length of the 'Hello world!' string
global _start
extern GetStdHandle
extern WriteConsoleA
extern ExitProcess
section .text
_start:
; At _start the stack is 8 bytes misaligned because there is a return
; address to the MSVCRT runtime library on the stack.
; 8 bytes of temporary storage for `bytes`.
; allocate 32 bytes of stack for shadow space.
; 8 bytes for the 5th parameter of WriteConsole.
; An additional 8 bytes for padding to make RSP 16 byte aligned.
sub rsp, 8+8+8+32
; At this point RSP is aligned on a 16 byte boundary and all necessary
; space has been allocated.
; hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)
mov ecx, -11
call GetStdHandle
; WriteFile(hstdOut, message, length(message), &bytes, 0);
mov rcx, rax
mov rdx, message
mov r8, messageLen
lea r9, [rsp-16] ; Address for `bytes`
; RSP-17 through RSP-48 are the 32 bytes of shadow space
mov qword [rsp-56], 0 ; First stack parameter of WriteConsoleA function
call WriteConsoleA
; ExitProcess(0)
; mov rcx, 0
; call ExitProcess
; alternatively you can exit by setting RAX to 0
; and doing a ret
add rsp, 8+8+32+8 ; Restore the stack pointer.
xor eax, eax ; RAX = return value = 0
ret

NASM x86_64, Redifining Labels

My Goal is to redifine an existing label in the .data section of my Nasm Code.
The expected result shoud be that the existing memory label gets overwritten by the same procedure
The occuring errormessages are:
exp3.asm:230: error: comma, colon, decorator or end of line expected after operand
exp3.asm:191: ... from macro `var' defined here
exp3.asm:230: warning: character constant too long
exp3.asm:191: ... from macro `var' defined here
exp3.asm:230: error: parser: instruction expected
exp3.asm:195: ... from macro `var' defined here
exp3.asm:231: error: comma, colon, decorator or end of line expected after operand
exp3.asm:191: ... from macro `var' defined here
exp3.asm:231: error: symbol `test' redefined
exp3.asm:195: ... from macro `var' defined here
exp3.asm:231: error: parser: instruction expected
exp3.asm:195: ... from macro `var' defined here
Ive tried to rearange the word types, but it just complicated the problem instead of solving it.
The Required Macros:
%macro ifexis 3
push rax ; make room
mov rax, %1 ; platziere wert in Vergleichsregister
test rax, rax ; wenn werte gleich oder nicht leer
jz [%2] ; Gehe zu erfolg
jmp [%3] ; gehe zu fail
pop rax ; clear rax
%endmacro
Checks if the value exists by loading the Contents in to RAX and then testing it against eachother
%macro var 2
ifexis %1, %%overwrite, %%establish ;<--------------------------------------- Für gleiche labels muss eine lösung gefunden werden
%%overwrite: ;<---------------------------------------------------------------
mov db[%1], %2 ;<-------------------------------------------------------------
jmp %%end;<-------------------------------------------------------------------
%%establish:;<----------------------------------------------------------------
section .data
%1: db %2
;db 0
section .text
%%end:
%endmacro
Test code:
section .text
global _start
_start:
var test, "a"
var test, "b"
Any aditional sources for learning Assembler are welcome

seek_cur command sets the cursor in an unknown place in the file

I have a file that contains one word on every line (the number of words and their length is unknown) and I need to rewrite those words into another file, starting with the last word and getting to the first one. When I print the last word in the file, I try to set the cursor (seek_cur) to seek for the next word, but it sets it in an unknown place. Tried printing the current cursor to see what happens and it gives characters like "#A".
The second jmp get_out stops the program after writing the last word, if it's deleted it gets to the jmp search tag and then it's printing the same last word infinitely.
.386
.model flat, stdcall
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;includem biblioteci, si declaram ce functii vrem sa importam
includelib msvcrt.lib
extern exit: proc
extern fopen: proc
extern fclose: proc
extern fscanf: proc
extern fprintf: proc
extern fseek: proc
extern fgets:proc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;declaram simbolul start ca public - de acolo incepe executia
public start
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;sectiunile programului, date, respectiv cod
.data
file_read db "r",0
file_write db "w",0
file_name_read db "read.txt",0
file_name_write db "write.txt",0
seek_end dd 2
seek_cur dd 1
seek_set dd 0
caracter_format db "%c",0
string_format db "%s",0
decimal_format db "%d",0
string db 0
caracter db 0
back dd 0
first_word db 0
.code
start:
push offset file_read
push offset file_name_read
call fopen
add esp,8
mov esi,eax
push offset file_write
push offset file_name_write
call fopen
add esp,8
mov edi,eax
;in first_word se pune cuvantul de pe prima linie ca sa fie posibila comparatia mai incolo si sa se iese din bucla cand se ajunge la primul cuvant
repeat_search_first_word:
push offset caracter
push offset caracter_format
push esi
call fscanf
add esp,12
inc back
cmp caracter,0Ah
je out_of_search_first_word
jmp repeat_search_first_word
out_of_search_first_word:
inc back
neg back
push seek_cur
push back
push esi
call fseek
add esp,12
neg back
push esi
push back
push offset first_word
call fgets
add esp,12
mov back,0
;incepe cautarea cuvintelor de la capat
push seek_end
push -1
push esi
call fseek
add esp,12
search:
push offset caracter
push offset caracter_format
push esi
call fscanf
add esp,12
inc back
cmp caracter,0Ah
jne is_caracter
push esi
push back
push offset string
call fgets
add esp,12
push offset string
push offset string_format
push edi
call fprintf
add esp,12
;testam daca cuvantul coincide cu primul (first_word)
mov ebx,0
mov bl,string
cmp bl,first_word
je get_out
add back,2
neg back
;!!!!!!!!!!!!!!
;problema pentru rularea infinita ii aici fiindca seek_cur muta cursorul intr-o zona necunoscuta din fisier
push seek_cur
push back
push esi
call fseek
add esp,12
mov back,0
jmp get_out ;linia 152 lasata fara comentariu permite afisare ultimului cuvant fara sa intre in rularea infinita a buclei
jmp search
is_caracter:
push seek_cur
push -2
push esi
call fseek
add esp,12
jmp search
get_out:
push edi
call fclose
add esp,4
push esi
call fclose
add esp,4
push 0
call exit
end start
read.txt contains:
abc
defg
hijklm
write.txt should be:
hijklm
defg
abc
string db 0 reserves space for 1 byte (initialized to zero).
You then call fgets(fp, string, back), which will overwrite later things in your data section if it reads more than 1 byte (including the terminating 0).
Use a bigger buffer in the BSS, like a couple MB or something.
Use a debugger to trace function calls / system calls. On Linux you could use ltrace to trace the libc stdio functions, or strace to trace the system calls they use. On Windows IDK. You can always step through and look at the args you've pushed on the stack before each call to make sure they're sane, but it's often easier to see a log-file style of listing when looking for one with the wrong args.

LC-3 Instruction Understanding

Hey Stackoverflow I was going over some example code our professor has left us to study with, and I've had some problems understanding what some of the codes mean and it doesnt help that some of his comments are vague. the first is R3,R1,0; check for end of line, the second thing I dont get is really the logic behind the beginning of the placeolnul, and lastly the .fill values for negeol which seem oddly specific but i have no idea why. if you could really help me with those issues it would really help me understand the code alot better.
.orig x3000
getstring:
lea r0,prompt ;get string prompt
puts
ld r1,negeol ;to test end of line
lea r2,rdbuff ;prep to read string
rdloop:
getc ;get string char
out
str r0,r2,0 ;store it
add r3,r1,r0 ;check for end of line
brz placeeolnul ;if so process
add r2,r2,1 ;ready for next char
br rdloop ;get it
placeeolnul:
and r0,r0,0 ;overwrite eol with
str r0,r2,0 ;nul
lea r1,rdbuff ;get address for len
jsr strlen ;get length
add r0,r0,0 ;if 0
brz quit ;then prog finished
trap xfc ;print length
lea r0,colon ;print colon
puts
lea r0,eol ;print lf
puts
br getstring ;go again
quit
halt
prompt: .stringz "Enter a string:"
eol: .fill x000d ; or x000a
.fill x0000
negeol: .fill xfff3 ; or xfff6
colon: .fill x003a
rdbuff .blkw 80
; length subroutine
strlen:
and r0,r0,0 ;counter for length
st r2,saveX2 ;save regs used
st r3,saveX3
add r2,r1,0 ;copy of string addr
cloop:
ldr r3,r2,0 ;get char
brz exit ;check for nul
add r0,r0,1 ;incr counter
add r2,r2,1 ;go to next char
br cloop ;process it
exit:
ld r2,saveX2 ;restore used regs
ld r3,saveX3
ret
saveX2: .blkw 1
saveX3: .blkw 1
.end
In regards to this:
add r3,r1,r0 ;check for end of line
Here he is setting up for the subsequent "brz" to branch on zero.
So we are adding the contents of registers r1 and r0 and putting them in r3, so that if r3 is zero, we will branch in the next line:
brz placeeolnul ;if so process
Remember that r1 is already pre-loaded with a value based on this code:
ld r1,negeol ;to test end of line
which has loaded r1 with the value at the tag negeol per this code:
negeol
.fill xfff3 ; or xfff6
So this is just a quick way to detect if an EOL character has been found by adding the compliment of the EOL character, which presumably here is xfff3.
Regarding the brz statement and the logic for it (your 2nd question):
brz placeeolnul ;if so process
As mentioned, we are branching here if the add is zero. If we do not branch (meaning we did not find a EOL character), then we will continue, but that continuation will essentially loop back to rdloop tag:
add r2,r2,#1 ;ready for next char
br rdloop ;get it
If we DO jump via the brz line, that means we got the entire string, and we are ready to process it.... so jumping to placeeolnul just puts us into the code where we can process the string:
and r0,r0,#0 ;overwrite eol with
str r0,r2,#0 ;nul
.... etc...
Not sure if you have questions with this part of the code as well.
Hope this helps.
Jeff

How do I print a float value using printf in NASM?

I have this code that is suppose to print out a floating point value using _printf:
extern _printf
global _main
section .data
mensaje: db 'The number is %f', 10, 0
numero1: db 34.25
_main:
push numero1
push mensaje
call _printf
add esp, 8
ret
The output I get is:
The number is 0.000000
The output I expect is:
The number is 34.250000
What is wrong with my code, and what must be done to get the desired output?
EDITED:
The solution is:
extern _printf
global _main
section .data
mensaje: db 'The number is %f', 10, 0
numero1: dd 34.25
section .text
_main:
sub esp, 8
fld dword [numero1]
mov ebx, numero1
fstp qword [esp]
push mensaje
call _printf
add esp, 12
ret
The correct output is:
The number is 34.250000
#MichaelPetch Thank you very much. I am sorry to everybody, my english is bad.

Resources