Read only the first byte of a string - nasm

Previously I asked how I could send only the first byte of a string to a record, I was told that reading only the first byte of the string, but I don't know how to do it, please help.

To move the first byte of the string into al (which is the lowest byte of eax), use
mov al, [string]
If you want to move the byte into the low byte of eax and zero out the rest of eax, you can do
movzx eax, byte [string]
ref

Related

Why am I getting unexpected results when getting and displaying a character from a string?

I'm trying to get the second character of a string (eg e in Test). Using emu8086 to compile.
When I do:
str db 'Test$'
...
mov si, 1 ; get second character of str
mov bl, str[si] ; store the second character
mov ah, 2 ; display the stored character
mov dl, bl
int 21h
The output is e.
But when I do:
str db 25
db ?
db 25 dup (?)
...
mov ah, 0ah ; accept a string
lea dx, str ; store input in variable str
int 21h
mov si, 1 ; get second character of str (??)
mov bl, str[si] ; store the second character
mov ah, 2 ; display the stored character
mov dl, bl
int 21h
I get ♦.
When I change the second snippet's "get second character of str" portion to this:
mov si, 3 ; get second character of str (why is it '3' instead of '1'?)
mov bl, str[si] ; store the second character
I get e.
I don't understand. While it works in the first snippet, why, in the second snippet, do I have set SI to 3 instead of 1, if I'm trying to reference the second character of the string? Or is the method I'm using misled?
str[si] is not some kind of type/array access, but it will translate into instruction memory operand like [si+1234], where "1234" is offset, where the label str points to in memory.
And in your second example the str label points at byte with value 25 (max length of buffer), then str+1 points at returned input length byte (that's the ♦ value you get on output, if you try to print it out as character), and str+2 points at first character of user input. So to get second character you must use str+3 memory address.
The memory is addressable by bytes, so you either have to be aware of byte-size of all elements, or use more labels, like:
str_int_0a: ; label to the beginning of structure for "0a" DOS service
db 25
db ?
str: ; label to the beginning of raw input buffer (first char)
db 25 dup (?)
Then in the code you use the correct label depending on what you want to do:
...
mov ah, 0ah ; accept a string
lea dx, str_int_0a ; store input in memory at address str
int 21h
mov si, 1 ; index of second character of str
mov bl, str[si] ; load the second character
mov ah, 2 ; display the stored character
mov dl, bl
int 21h
...
You should use some debugger and observe values in memory, and registers, and assembled instructions to get the better feel for how these work inside the CPU, how segment:offset addressing is used to access memory in 16b real mode of x86, etc...

Store a string in register

I am trying to concatenate two strings in assembly language.
mov esi, str1
mov eax, str1
mov edx, [str2]
call slen
mov [esi+eax-1], edx
Everything works exactly fine except that only 4 characters of the second string gets appended. I know the reason for its occurrence, but I can't seem to find any solution.
You cannot store any string in a register. It has to be equal or smaller than register size (assuming we're talking about ASCII-encoded strings) because a register has a fixed size.

how to store strings in 8086

Im using emu8086.
For example i have a macro called 'store' which takes a string and stores it in an array, how do i do that?
sample code:
arrayStr db 30 dup(' ')
store "qwerty"
store MACRO str
*some code here which stores str into arrayStr*
endm
Most examples i found on the internet revolve around already having the string stored in a variable (ex. string db (some string here)) but i want something where the variables get initialized empty first.
Do you want to change a variable at runtime? In this case take a look at the PRINT-macro in emu8086.inc. A few changes and you've got a STORE-macro:
store MACRO str
LOCAL skip_data, endloop, repeat, localdata
jmp skip_data ; Jump over data
localdata db str, '$', 0 ; Store the macro-argument with terminators
skip_data:
mov si, OFFSET localdata
mov di, OFFSET msg
repeat: ; Loop to store the string
cmp byte ptr [si], 0 ; End of string?
je endloop ; Yes: end of loop
movsb ; No: Copy one byte from DS:SI to ES:DI, inc SI & DI
jmp repeat ; Once more
endloop:
ENDM
crlf MACRO
LOCAL skip_data, localdata
jmp skip_data
localdata db 13, 10, '$'
skip_data:
mov dx, offset localdata
mov ah, 09h
int 21h
ENDM
ORG 100h
mov dx, OFFSET msg
mov ah, 09h
int 21h
crlf
store "Hello!"
mov dx, OFFSET msg
mov ah, 09h
int 21h
crlf
store "Good Bye."
mov dx, OFFSET msg
mov ah, 09h
int 21h
mov ax, 4C00h
int 21h
msg db "Hello, World!", '$'
It depends on, what you want to do with the string
Here are some examples:
ASCIZ-String
The string ends with a zero-byte.
The advantage is that everytime the CPU loads a single byte from the RAM the zero-flag is set if the end of the string is reached.
The disadvantage is that the string mustn't contain another zero-byte. Otherwise the program would interprete an earlier zero-byte as the end of the string.
String input from DOS-Function Readln (int 21h/ ah=0ah)
The first byte defines, how long the string inputted by the user could be maximally. The effective length is defined in the second byte. The rest contains the string.
String which is ready to be outputted using WriteLn (int 21h/ ah=09h)
The string ends with a dollar-sign (ASCII 36).
The advantage is that your programm can output the string using a single function (int 21h/ ah=09h).
The disadvantage is that the string mustn't contain another dollar-sign. Otherwise the program would interprete an earlier dollar-sign as the end of the string.
String whose length is defined in a word/byte at the beginning of the String
Unformatted String
You don't have to save the length in a variable nor marking the end, if you save the length to a constant which you can put in a register (e.g. in CX)

How to compare two strings in assembly?

I'm new in assembly. I want to compare two string using "cmps". I read some examples and I write this :
GETSTR MACRO STR
MOV AH,0AH
LEA DX,STR
INT 21H
ENDM
PRINTSTR MACRO STR
MOV AH,09H
LEA DX,STR
INT 21H
ENDM
EXTRA SEGMENT
DEST DB ?
EXTRA ENDS
DATA SEGMENT
SOURCE DB ?
STR1 DB 0AH,0DH,'ENTER STR : ' ,'$'
ENTER DB 10,13,'$'
SAME DB 0AH,0DH,'TWO STR ARE THE SAME ' ,'$'
NSAME DB 0AH,0DH,'TWO STR ARE NOT THE SAME ' ,'$'
USER DB 6,10 DUP('$')
USER1 DB 6,10 DUP('$')
DATA ENDS
CODE SEGMENT
ASSUME DS:DATA,CS:CODE,ES:EXTRA
START:
MOV AX,DATA
MOV DS,AX
MOV AX,EXTRA
MOV ES,AX
PRINTSTR STR1
GETSTR USER1
PRINTSTR STR1
GETSTR USER
LEA BX,USER
MOV SI,BX
LEA BX,USER1
MOV DI,BX
CLD
MOV CX,5
REPE CMPSB
JCXZ MTCH
PRINTSTR NSAME
JMP ENDPR
MTCH:
PRINTSTR SAME
ENDPR:
MOV AH,4CH
INT 21H
CODE ENDS
END START
I have some question:
what is exactly the numbers 6,10 in the code below :
USER DB 6,10 DUP('$')
Is there any mistake with the Macros?
Is it necessary to declare EXTRA SEGMENT ?
For any similar strings input the output is : "they are not the same?" what is the reason?
The number 6 defines the number of characters plus 1 that you want DOS to input. The number 10 defines the length of the buffer that follows. Actually the number 7 would have been enough!
The macros seem fine.
You don't need the EXTRA segment. Moreover putting it into ES is wrong because both strings that you will be comparing are in the DATA segment.
Also both LEA instructions must fetch an address that is 2 higher. The first byte will still be the maximum number of bytes to read (6) and the second byte will be the number of bytes actually read [0,5]
The comparison you're making indifferably uses 5 characters. If you don't take into account the real number of characters as reported by DOS in the second byte it's no wonder results might not be satisfying.

How to replace chars in a string

If I have a string like 'aabbcc' how can I change the 2nd and 4th char to another char?
EDIT: I'm using NASM on Windows, and yes, this is part of a big homework assignment.
Substitute with 'd':
lea eax, addr string ( or mov eax, string)
mov byte ptr [eax+1], 64h
mov byte ptr [eax+3], 64h
In Java and many other languages, you can't. Strings are immutable objects. In
many other languages you shouldn't. Strings you did not create a likely to be literals,
and changing them changes the string for some indefinite value of "everyone".

Resources