FASM - how to do this without stack? - fasm

I wrote program that asking user for his name and displaying it on screen in FASM. I used stack, but I was wondering how I can do it without it.
This is working code:
format elf executable
entry _start
segment readable
msg db 'What is your name: '
msg.length = $-msg
msg2 db 'Your name is: '
msg2.length = $-msg2
segment readable writeable
name db ?
segment readable executable
_start:
mov eax,4
mov ebx,1
mov ecx,msg
mov edx,msg.length
int 80h
mov eax,3
mov ebx,1
mov ecx,name
mov edx,20
int 80h
push eax
mov eax,4
mov ebx,1
mov ecx,msg2
mov edx,msg2.length
int 80h
mov eax,4
mov ebx,1
mov ecx,name
pop edx
int 80h
mov eax,1
mov ebx,0
int 80h
I tried to do something like that:
format elf executable
entry _start
segment readable
msg db 'What is your name: '
msg.length = $-msg
msg2 db 'Your name is: '
msg2.length = $-msg2
segment readable writeable
name db ?
name.length db ?
segment readable executable
_start:
mov eax,4
mov ebx,1
mov ecx,msg
mov edx,msg.length
int 80h
mov eax,3
mov ebx,1
mov ecx,name
mov edx,20
int 80h
mov dword [name.length],eax
mov eax,4
mov ebx,1
mov ecx,msg2
mov edx,msg2.length
int 80h
mov eax,4
mov ebx,1
mov ecx,name
mov edx,dword [name.length]
int 80h
mov eax,1
mov ebx,0
int 80h
Code is compiling without errors, but when I'm running it and when I input the name (e.g "debos") I'm getting:
Your name is: d and some weird char at the end
instead of:
Your name is debos like with the first code.
Can someone tell me what is wrong with my code?

name should be declared as an array of bytes, not as a single byte (db).
segment readable writeable
name db 100 dup(?) ;or simply name rb 100
name.length dd ?
name.length should be a dword, not a byte. In FASM executable format, the code segment comes right after the last byte of the data segment, so it explains why it prints garbage characters because it overlaps. This is just the nature of the ELF executable format.

msg.length is a constant so you can not overwrite it. If you want so, you should store this in a variable.

Related

Retrieve data from an array

So, basically I just want to display the first data from array which is userbalanceIndex1 from userbalanceIndex.
But I get an error which is
DEMO.ASM(29): Out of memory
29 line: mov bl,(userbalanceIndex +1)
Here is my code:
.model small
.stack 100H
.data
userbalanceIndex db usrbalance1, usrbalance2, usrbalance3, usrbalance4
usrbalance1 Db 1
usrbalance2 Db 9
usrbalance3 Db 6
usrbalance4 Db 0
.code
OUTPUT MACRO DIGIT
MOV AH, 02H
MOV DL, DIGIT
INT 21H
ENDM
main proc
MOV AX,#DATA
MOV DS,AX
mov al, userbalanceIndex
mov cx, 0
a:
inc userbalanceIndex
mov bl, (userbalanceIndex + 1)
loop a
OUTPUT bl
mov ah, 4ch
int 21h
main endp
end main

Define a string array using NASM - Prototype give the number of days in a month

Well as the title said , I am working on a NASM project: the idea is simple , I need to take a month from input (string) and give the number of day (using cases regarding numbers). Until now I spent the day dealing with reading/printing and finally comparing 2 strings , which I could do after some struggles and thanks to some old questions I've found here and on other forums.My current problem is that I need to put the months (names) in an array so I could do the comparing with a loop, I saw on another answer that I could label the 'array' like this:
label: db str1,str2
I tried that and when I try printing with just the label I get only the last month (I tried label+i but I still get the same thing)
Well, here is a part of my code:
segment .data
org 100h
msg db "a"
mon1 db "janvier",0
mon2 db "fevrier",0
mon3 db "mars",0
mon4 db "avril",0
mon5 db "mai",0
mon6 db "juin",0
mon7 db "juillet",0
mon8 db "aout",0
mon9 db "septembre",0
mon10 db "octobre",0
mon11 db "novembre",0
mon12 db "decembre",24h
mo dw 1,2,3,4,5,6,7,8,9,10,11,12
mon:
dw mon1,mon2,mon3,mon4,mon5,mon6,mon7,mon8,mon9,mon10,mon11,mon12
segment .code
mov dx,mon
mov ah,09h
int 21h
edit2: I tried the solution given by #ecm , I had to make a few change because It gave me some errors then after i could finally run it It went to error, Here is the whole code:
segment .code
display_month:
; takes month 1 to 12 in ax
dec ax ; make number 0-based
cmp ax,amount
jae error ; if out of range -->
add ax, ax ; make it an index into a word array
mov bx, ax ; use bx for addressing memory
mov dx, word [mon+ bx] ; access array entry
mov di, dx
mov cx, -1
mov al, 0
repne scasb
not cx
dec cx ; string length
mov bx, 1
mov ah, 40h
int 21h ; write to stdout
clc ; indicate not error
mov dx,msg1
mov ah,09h
int 21h
mov ah,0Ah
mov dx, len ;start of buffer
int 21h
mov ah,02h
mov dl,10
int 21h
mov dl,13
int 21h
mov bx,act
mov dx,buffer
add dl,byte [bx]
mov bx,dx ; move pointer into BX
mov byte [bx],24h ; put the $ there.
; compare input with msg variable(a placeholder for the moment ) I want to compare with the mon array values , and then use the index as an argument to call the cond procedure.
mov ax,msg
mov si,ax
mov ax,buffer
mov di,ax
cmpsb
jz Yep ; if strings equal goto Yep
jmp Nope ; goto Nope
Yep:
mov dx,good
mov ah,9
int 21h ; tell the user it's good
Nope:
mov dx,bad
mov ah,9
int 21h ; tell the user it's bad
end:
mov ah,4Ch
int 21h
ret
error:
stc
retn
cond:
cmp ax,2
je fev
cmp ax,7
jg odd
jle even
else: mov bx,31
jmp endif
fev: mov bx,28
odd: test ax,1
jnz trente
jmp else
even: test ax,1
jp trente
jmp else
trente: mov bx,30
endif: ret
segment .data
org 100h
;; variables declaration
msg1 db "Veullez entrer un mois:",24h
msg db "a",24h
mon1: db "janvier",0
mon2: db "fevrier",0
mon3: db "mars",0
mon4: db "avril",0
mon5: db "mai",0
mon6: db "juin",0
mon7: db "juillet",0
mon8: db "aout",0
mon9: db "septembre",0
mon10: db "octobre",0
mon11: db "novembre",0
mon12: db "decembre",0
good db "Bon choix!",24h
bad db "Mauvais choix!",24h
mon:
start:
dw mon1,mon2,mon3,mon4,mon5,mon6,mon7,mon8,mon9,mon10,mon11,mon12
tend:
len db 254 ; a fair amount of space
act db 0 ; will be filled with actual amount of chars received
buffer times 254 db 0
size equ tend - start
amount equ size / 2
I forgot to add how I am compiling , well I am using dosbox to run .com files , because they don't work on windows 10 , and I use the command : nasm name.asm -o name.com to create the .com file and then I just open it in dos.
EDIT: Well I struggled a lot to make that happen , I couldn't do it even thought I tried different ways , the last thing I went with was to use the first month and keeping adding the size of months to pass to the other ones (i.e mon1+8 gives me mon2 ...) but then I encountered with the difference in sizes , so I changed all the months to just 3 letters (4 for june) so I could move with multiples of 4 but then I couldn't go all the way to the end .. So after that I just decided to use the mon(i) by calling the names and repeating the manoeuvre , which seemed to work thought I encountered a problem with comparing (I am still trying to figure out) , well here is the last version until I figure out how to fix that.The problem at this moment is that even if I type something different than the mon1 to mon12 I get this:Le mois de 'input' est de 30 jours while normally it should take me back to the start of the nope label.
segment .code
org 100h
mov dx,msg1
mov ah,09h
int 21h
here: mov ah,0Ah
mov dx, len
int 21h
mov ah,02h
mov dl,10
int 21h
mov dl,13
int 21h
mov bx,act
mov dx,buffer
add dl,byte [bx]
mov bx,dx
mov byte [bx],24h
jmp comp
yep:
mov dx,g1
mov ah,09h
int 21h
mov dx,buffer
int 21h
mov dx,g2
int 21h
mov ax, [i]
call cond
mov ah,02h
mov dl,bh
int 21h
mov dl,bl
int 21h
mov dx,g3
mov ah,09h
int 21h
jmp end
comp: mov bx,0
mov [i],bx
jan: call inct
mov bx,buffer
mov si,bx
mov bx,mon1
mov di,bx
cmpsb
jz yep
fevr: call inct
mov bx,buffer
mov si,bx
mov bx,mon2
mov di,bx
cmpsb
jz yep
mar: call inct
mov bx,buffer
mov si,bx
mov bx,mon3
mov di,bx
cmpsb
jz yep
avr: call inct
mov bx,buffer
mov si,bx
mov bx,mon4
mov di,bx
cmpsb
jz yep
mai: call inct
mov bx,buffer
mov si,bx
mov cx,mon5
mov di,cx
cmpsb
jz yep
juin: call inct
mov bx,buffer
mov si,bx
mov bx,mon6
mov di,bx
cmpsb
jz yep
jmp jui
jui: call inct
mov cx,buffer
mov si,cx
mov cx,mon7
mov di,cx
cmpsb
jz yep
aout: call inct
mov cx,buffer
mov si,cx
mov cx,mon8
mov di,cx
cmpsb
jz yep
jmp sep
sep: call inct
mov bx,buffer
mov si,bx
mov cx,mon9
mov di,cx
cmpsb
jz yep
jmp oct
oct: call inct
mov bx,buffer
mov si,bx
mov cx,mon10
mov di,cx
cmpsb
jz yep
jmp nov
nov: call inct
mov bx,buffer
mov si,bx
mov cx,mon11
mov di,cx
cmpsb
jz yep
jmp dect
dect: call inct
mov bx,buffer
mov si,bx
mov cx,mon12
mov di,cx
cmpsb
jz yep
jmp nope
nope:
mov dx,bad
mov ah,9
int 21h
jmp here
end:
mov ah,4Ch
int 21h
ret
inct:
push bx
mov bx,[i]
inc bx
mov [i],bx
pop bx
ret
cond:
cmp ax,2
je fev
cmp ax,6
je th
cmp ax,8
je th
cmp ax,7
jg odd
jle even
else: mov bl,'1'
mov bh,'3'
jmp endif
fev: mov bl, '8'
mov bh,'2'
jmp endif
th: jmp else
odd: test ax,1
jnz trente
jmp else
even: test ax,1
jp trente
jmp else
trente: mov bh,'3'
mov bl,'0'
endif: ret
segment .data
i db 0
msg1 db "Veullez entrer un mois:",24h
mon1: db "janvier",24h
mon2: db "fevrier",24h
mon3: db "mars",24h
mon4: db "avril",24h
mon5: db "mai",24h
mon6: db "juin",24h
mon7: db "juillet",24h
mon8: db "aout",24h
mon9: db "septembre",24h
mon10: db "octobre",24h
mon11: db "novembre",24h
mon12: db "decembre",24h
g1 db "Le mois de",20h,24h
g2 db 20h,"est de",20h,24h
g3 db 20h,"jours",24h
bad db "Le mois saisi n'est pas correct!",10,13,"Veuillez entrer un autre mois:",24h
len db 254 ; a fair amount of space
act db 0 ; will be filled with actual amount of chars received
buffer times 254 db 0
Try this:
segment .code
display_month:
; takes month 1 to 12 in ax
dec ax ; make number 0-based
cmp ax, montab.amount
jae .error ; if out of range -->
add ax, ax ; make it an index into a word array
mov bx, ax ; use bx for addressing memory
mov dx, word [montab + bx] ; access array entry
mov di, dx
mov cx, -1
mov al, 0
repne scasb
not cx
dec cx ; string length
mov bx, 1
mov ah, 40h
int 21h ; write to stdout
clc ; indicate not error
retn
.error:
stc
retn
segment .data
mon1: db "janvier",0
mon2: db "fevrier",0
mon3: db "mars",0
mon4: db "avril",0
mon5: db "mai",0
mon6: db "juin",0
mon7: db "juillet",0
mon8: db "aout",0
mon9: db "septembre",0
mon10: db "octobre",0
mon11: db "novembre",0
mon12: db "decembre",0
align 2
montab:
.:
dw mon1
dw mon2
dw mon3
dw mon4
dw mon5
dw mon6
dw mon7
dw mon8
dw mon9
dw mon10
dw mon11
dw mon12
.end:
.size equ .end - .
.amount equ .size / 2
You could use 12 as the hardcoded array length in this case. But using equates for the length and amount of entries is useful for static data arrays more generally.
ETA: I added alignment for the table, which is good for performance. Not needed but it doesn't cost much.
Note that I dropped the org directive from my example. This is because I am presenting just one function that should be called from other program logic. If you're assembling into a simple style flat .COM executable for 86-DOS, you still need to include the org 256 at some point.
Here's a breakdown of your question's attempt:
msg db "a"
This seems like an unused leftover.
mon1 db "janvier",0
mon2 db "fevrier",0
mon3 db "mars",0
mon4 db "avril",0
mon5 db "mai",0
mon6 db "juin",0
mon7 db "juillet",0
mon8 db "aout",0
mon9 db "septembre",0
mon10 db "octobre",0
mon11 db "novembre",0
These are all fine, they define ASCIZ strings. (The Z stands for zero-terminated.)
mon12 db "decembre",24h
This one uses a different terminator, in this case the dollar sign (24h = 36). It is not appropriate to mix terminators between array entries. Either use all ASCIZ or all CP/M-style dollar-terminated strings.
mo dw 1,2,3,4,5,6,7,8,9,10,11,12
This is useless. If you wanted to map a number from 1 to 12 as index into this array, the original value would be found at that array entry. If the entries had different numbers this type of array could be useful, but not with identity mapping.
mon:
dw mon1,mon2,mon3,mon4,mon5,mon6,mon7,mon8,mon9,mon10,mon11,mon12
This is essentially correct. (I put each entry on its own line and prepended the align directive, but neither is absolutely necessary.)
mov dx,mon
mov ah,09h
int 21h
This loads the address of your message table into dx then passes dx to interrupt 21h function 09h. This function expects a dollar-terminated string, so only your December string would work. More importantly, it will try to display the literal bytes that make up your array. You need to, instead, dereference a pointer to one of your array's entries to load the address stored therein, which is the address of the associated message string.

Read a line from File and pass it to variable, then proceed to next line (Assembly 8086)

this is my first post so I'm sorry in advance if I did it wrongly (in any ways).
So what I am facing now is, I have a a file (name.txt) and I want to pass the first line to buffer1 , second line to buffer2 and so on.
Extra Info :
The maximum line of the file is going to be 10.
The maximum length of the string is 27(data)+1(dollar sign)+2(CR LF) or so I think.
I created 5 buffer for this example
The example of the string is "1washingmachine"
name.txt is already created
.
.model small
.stack 64
.data
filename db "name.txt",0
handler dw ?
strPrompt db 10,13,"enter:$"
strInput label byte
max db 28 ;max name is 20 , + 1 for index , 6 for time , 1 for $
act db ?
data db 28 dup ('$')
buffer1 db 30 dup ('$')
buffer2 db 30 dup ('$')
buffer3 db 30 dup ('$')
buffer4 db 30 dup ('$')
buffer5 db 30 dup ('$')
newLine db 10,13
.code
main proc far
;INITIALIZE DATA SEGMENT.
mov ax,#data
mov ds,ax
;CREATE FILE.
mov ah, 3dh
mov al, 2
lea dx, filename
int 21h
;PRESERVE FILE HANDLER RETURNED.
mov handler, ax
;READ STRING
MOV AH, 3FH ; read file
MOV BX, handler ; copy handle into BX
MOV CX,30 ; set count to read 28+2
lea dx,buffer1
INT 21H ; AX = bytes read
MOV AH, 3FH ; read file
MOV BX, handler ; copy handle into BX
MOV CX,30 ; set count to read 28+2
lea dx,buffer2
INT 21H
MOV AH, 3FH ; read file
MOV BX, handler ; copy handle into BX
MOV CX,30 ; set count to read 28+2
lea dx,buffer3
INT 21H
MOV AH, 3FH ; read file
MOV BX, handler ; copy handle into BX
MOV CX,30 ; set count to read 28+2
lea dx,buffer4
INT 21H
MOV AH, 3FH ; read file
MOV BX, handler ; copy handle into BX
MOV CX,30 ; set count to read 28+2
lea dx,buffer5
INT 21H
mov ah,09h
lea dx,buffer1
int 21h
mov ah,09h
lea dx,buffer2
int 21h
mov ah,09h
lea dx,buffer3
int 21h
mov ah,09h
lea dx,buffer4
int 21h
mov ah,09h
lea dx,buffer5
int 21h
;input string to write in file
mov ah,09h
lea dx,strPrompt
int 21h
mov ah,0ah
lea dx,strInput
int 21h
;WRITE STRING.
mov ah, 40h
mov bx, handler
mov ch,0
mov cl, act ;STRING LENGTH.
inc cx
mov dx, offset data
int 21h
lea dx,newLine
mov bx,handler
mov cx,2
mov ah,40h
int 21h
;CLOSE FILE (OR DATA WILL BE LOST).
mov ah, 3eh
mov bx, handler
int 21h
;FINISH THE PROGRAM.
mov ax,4c00h
int 21h
main endp
end main
Hopefully someone from StackOverflow can help me with this, either guidance or solution will do !

Nasm Assembly: I'm trying to copy a string and then search for a specific word in it, change it, and print it. Stuck on the copying part.

I'm stuck at figuring out to copy the string source to target, which should be initialized to all zeroes. It appears as though I need to find the size of the string, start a counter register, and push stringitem[counter] to the stack, increment counter register. I can't figure out how to even get started, let alone search for a word in the string.
Thanks!
bits 64
global main
extern printf
section .text
main:
; function setup
push rbp
mov rbp, rsp
sub rsp, 32
;
lea rdi, [rel message]
mov al, 0
call printf
;
lea rdi, [rel source]
mov al, 0
call printf
;
;mov edi, source
;mov esi, target
;lea rdi, [esi]
;mov al, 0
;call printf
;mov ecx,sizeof source -1
; mov esi,0
;L1:
; mov eax,source[esi];
; push eax
; inc esi
; loop L1
; function return
mov eax, 0
add rsp, 32
pop rbp
ret
section .data
message: db 'Project',0x0D,0x0a,'Author',0x0D,0x0a,0
source: db 0x0D,0x0a,"I can't figure out how to copy this text to target.",0x0D,0x0a,0
target: db '0000000000000000000000000000000000000000000',0x0D,0x0a,0
For your data memory layout this will do
lea rdi, [rel target]
lea rsi, [rel source]
mov rcx, target-source
cld
rep movsb
Otherwise as Jester said, a simple byte-to-byte copy will also do
lea rdi, [rel target]
lea rsi, [rel source]
cld
.copy:
lodsb
stosb
test al, al
jnz .copy

Character counting from big files in assembly

This should be counting every character in file but its working only for smaller files and i need it to work for files containing more than 32768 characters
fn DB strsize DUP ('$');
bsize equ 32768
buff db bsize dup ('$')
read proc
mov ah,3dh ;open
mov al,0 ; read only mode
mov dx,offset fn ; offset of file name
int 21h ; file handle
jc jmpchyba
ret
endp
BITY proc
mov full,00
mov actual,00
jmpback:
call read
mov actual,00
mov bx,ax;offset buff
mov ah,3fh
mov cx,bsize ; count bytes
mov dx,offset buff
int 21h ;
mov actual,ax
mov bx,actual
add full,bx
cmp actual,bsize
je jmpback
vypis kolko
mov ax,full
call convasci;this is working convert from binary to asci
ret
endp
Firstly define full as a dword. Then use this code
mov actual,ax
mov bx,actual
add full,bx
adc full+2,0
Obviously the conversion routine convasci should also be changed to deal with a dword.
The proc read actually opens the file! You should certainly not keep calling it from the BITY proc.
Rename read as open and place call open before the label jmpback:
Open proc
mov ah,3dh ;open
mov al,0 ; read only mode
mov dx,offset fn ; offset of file name
int 21h ; file handle
jc jmpchyba
ret
endp
BITY proc
mov full,0
mov full+2,0
call Open
mov bx,ax ;Handle!!!
jmpback:
mov actual,00
mov ah,3fh
mov cx,bsize ; count bytes
mov dx,offset buff
int 21h ;
mov actual,ax
add full,ax
adc full+2,0
cmp ax,bsize
je jmpback

Resources