I am attempting to copy a string into an array in the Assembly language. Basically the program asks a user for their name, then adds them to a list of users. I can read in the string just fine, but am unsure how to store string values into an array. I know the eax value stores the length of the string, but I need to store the string itself. Any tips on how to do this?
Thanks in advance.
To store the strings in an "array" you store the addresses of the start of the strings.
maybe you mean like this :
.model small
.code
org 100h
data:
kal1 db 'MIKROSKIL$'
kal2 db 11 dup(?)
code1:
mov bx,0
ulang1:
mov dl,kal1[bx]
mov kal2[bx],dl
inc bx
cmp dl,'$'
jne ulang1
mov ah,9
mov dx,offset kal2
int 21h
int 20h
end data
Related
I'm working on a C program that calls an assembly function passing an array as argument.
In the assembly code (for 8086), I'm able to get the address of the array in memory and to save the address in ES:BX but after that I need to copy the values to the array BARCODE but I can't find any way of achieving that.
My code looks something like this:
Code:
unsigned char computeControlDigit(char* barCodeASCII);
int main( void ){
char barCodeStr[14]
unsigned char controlDigitCheck;
controlDigitCheck = computeControlDigit(barCodeStr);
}
Assemby code:
_DATA SEGMENT WORD PUBLIC 'DATA'
BARCODE DB 13 DUP(?)
_DATA ENDS
PUBLIC _computeControlDigit
_computeControlDigit PROC FAR
PUSH BP
MOV BP, SP
PUSH ES
LES BX, [BP+6]
; code to copy from memory to
; array and code of operations on the array
POP ES
POP BP
RET
_computeControlDigit ENDP
_TEXT ENDS
END
Any help would be wery welcome.
In the large memory model all data and code is FAR and must be referenced through the proper segment. In the code below I load the pointer to the source string barcodestr into DS:SI and BARCODE into ES:DI. I then read the character from the barcodestr array with LODSB and save it to BARCODE with STOSB. The copy is finished when the NUL terminator has been reached.
Assuming the Direction Flag (DF) is set to 0 (forward movement):
STOSB is similar1 to doing:
mov [ES:DI], al
lea di, [DI + 1] ; Increment DI by 1 without altering flags
LODSB is similar1 to doing:
mov al, [DS:SI]
lea si, [SI + 1] ; Increment SI by 1 without altering flags
I don't know if you are using MASM or TASM as an assembler so I provide a version for both. Example TASM code that simply copies a NUL terminated string is as follows:
.MODEL LARGE, C
PUBLIC computeControlDigit
_DATA SEGMENT WORD PUBLIC 'DATA'
BARCODE DB 13 DUP(?)
_DATA ENDS
_TEXT SEGMENT WORD PUBLIC 'TEXT'
ASSUME DS:_DATA, CS:_TEXT
computeControlDigit PROC C FAR
ARG %%barcodestr:DWORD ; barcodestr is a FAR pointer (DWORD)
USES DS, SI, DI ; Save non-volatile registers
MOV AX, SEG BARCODE ; Get segment and offset (FAR PTR) of BARCODE
MOV ES, AX ; into ES:DI
MOV DI, OFFSET BARCODE
LDS SI, %%barcodestr ; Load barcodestr FAR pointer into DS:SI
JMP %%GETCHAR ; Get next character
%%NEXTCHAR:
STOSB ; Store character to ES:DI (BARCODE), DI++
%%GETCHAR:
LODSB ; Read character from DS:SI (barcodestr), SI++
TEST AL, AL ; Is it a NUL terminator?
JNZ %%NEXTCHAR ; If not go back and get next character
%%ENDLOOP:
STOSB ; Store NUL terminator at end of BARCODE
RET
computeControlDigit ENDP
_TEXT ENDS
END
Of course you do whatever processing you choose. I just did a straight copy of the data as an example.
If using MASM you may have to use a slightly different syntax:
.MODEL LARGE, C
PUBLIC computeControlDigit
_DATA SEGMENT WORD PUBLIC 'DATA'
BARCODE DB 13 DUP(?)
_DATA ENDS
_TEXT SEGMENT WORD PUBLIC 'TEXT'
ASSUME DS:_DATA, CS:_TEXT
computeControlDigit PROC FAR C USES DS SI DI barcodestr:DWORD
; DS, SI, DI are saved as they are non-volatile registers
; barcodestr is a FAR pointer (DWORD)
MOV AX, SEG BARCODE ; Get segment and offset (FAR PTR) of BARCODE
MOV ES, AX ; into ES:DI
MOV DI, OFFSET BARCODE
LDS SI, barcodestr ; Load barcodestr FAR pointer into DS:SI
JMP GETCHAR ; Get next character
NEXTCHAR:
STOSB ; Store character to ES:DI (BARCODE), DI++
GETCHAR:
LODSB ; Read character from DS:SI (barcodestr), SI++
TEST AL, AL ; Is it a NUL terminator?
JNZ NEXTCHAR ; If not go back and get next character
STOSB ; Store NUL terminator at end of BARCODE
RET
computeControlDigit ENDP
_TEXT ENDS
END
A raw version without using special assembler directives that may look more natural to you would be:
PUBLIC _computeControlDigit
_DATA SEGMENT WORD PUBLIC USE16 'DATA'
BARCODE:
DB 13 DUP(?)
_DATA ENDS
_TEXT SEGMENT WORD PUBLIC USE16 'TEXT'
ASSUME CS:_TEXT, DS:_DATA
_computeControlDigit:
push bp
mov bp,sp
push ds
push si
push di
mov ax,seg BARCODE
mov es,ax
mov di,offset BARCODE
lds si,dword ptr 6[bp]
jmp GETCHAR
NEXTCHAR:
stosb
GETCHAR:
lodsb
test al,al
jne NEXTCHAR
stosb
pop di
pop si
pop ds
pop bp
retf
_TEXT ENDS
END
Footnote
1LODSB and STOSB are similar to the equivalent code shown with the exception that LODSB and STOSB are executed in their entirety as one instruction each.
You can use
mov al,es:[bx]
to read a character from the string, but since this is large model, you'll need to create a far pointer to BARCODE. You might want to consider using ds:si for the input, and es:di for the output, since that would allow the code to lodsb and stosb.
I am trying to write an assembly program that uses a procedure to populate an array with values 1-100. The code that I have so far is as follows:
jmp main
first100 dw 100 dup (?)
main:
call prepare
call populate
mov ax, first100[0]
call putDec
mov ah, 04c
int 021
include ioProcs.inc
prepare:
mov ax, 1
mov bx, 0
mov cx, 100
ret
populate:
mov first100[bx], ax
inc ax
inc bx
loop populate
ret
However, the first value in the array first100 turns into 513 as opposed to 1. It is probably something simple, but where am I messing up?
Thank you much for your time.
As #Jester mentioned you need to increment bx by two bytes in the populate loop.
You are creating an array of type dw, that is a word. It has a size of two bytes.
I did a search on Stack Overflow, and I have not found anything similar to my problem. My problem is this: I have a code that opens a file and writes a message at the end. When I use int 21h to write to the file in the first time, it writes well if the file is empty, but if the file has content, the program adds to the end many trash bytes (characters like 畂 or another japanese or chinese characters).
I have checked that the program don't write more bytes than the message length. Please, help me. Here is my source code:
.model tiny
.code
main:
call delta
delta:
pop bp
sub bp, offset delta
mov ax, #code ;Get the address of code segment and store it in ax
mov ds, ax ;Put that value in Data segment pointer.
;Now, we can reference any data stored in the code segment
;without fail.
;Subroutines
open:
mov ax, 3D02H ;Opens a file
lea dx, [bp+filename];Filename
int 21h ;Call DOS interrupt
mov handle, ax ;Save the handle in variable
move_pointer_to_end:
mov bx, handle
mov ax,4202h ; Move file pointer
xor cx,cx ; to end of file
cwd ; xor dx,dx
int 21h
write:
mov ax, 4000H
mov bx, handle
lea dx, [bp+sign]
mov cx, 16
int 21H
exit:
mov ah,4Ch ;Terminate process
mov al,0 ;Return code
int 21h
datazone:
handle dw ?
filename db 'C:\A.txt', 0
sign db 'Bush was here!!', 0
end main
Please help me!!
That's because the file to which you're appending the data is encoded in unicode. If you write a file out from Notepad or another text editor and save it, you have to pick ANSI as the encoding. Then if you point your program at the ANSI encoded text file, it should append the string indicated with the expected result.
Unicode allocates two bytes for every character so in a hex editor you might see s.o.m.e.t.h.i.n.g. .l.i.k.e. .t.h.i.s. rather than something like this that you might expect for ANSI or UTF-8.
I am using MASM assembly and I am trying to write a loop that processes the string str1 byte-by-byte, changing each lowercase letter into the corresponding capital letter using bit operations. If the letter is already capital, leave it alone. Nothing seems to happen to my string str1 when I execute my code and I'm having difficulty figuring out why, maybe I shouldn't be processing my array as such, but nonetheless, here's the code:
.386
.MODEL FLAT
str1 dword "aBcD", cr, Lf, 0
....
.code
_start:
output str1
**sub esi, esi ; sum = 0
lea ebx, str1
top: mov al, [ebx + esi] ; attempting to move each character value from
str1 into the register al for comparison and
possible conversion to uppercase
add esi, 5
cmp al, 0
je zero
sub al, 20h** ; convert lowercase to corresponding uppercase
loop top
zero: output zeromsg ; for TESTING of al purposes only
done: output str1value
output str1
Nothing changes , and on top of the conversion not taking place, the string it printing in reverse order. why? prints out as: "DcBa". Any inquiry would be appreciated! Thanks in advance.
You must load the character, process it, and store it back. You don't store it.
Something like:
mov [esi+ebx], al
is missing.
Why do you sub 0x20 from the char? And why do you add 5 to esi?
Update
Before you start coding, you should think about what the required steps are.
Load the character.
If the character is 0 the string is done.
If the character is uppercase, convert it
Store the character
Adavance to the next character and back to 1
That's it. Now when you look at your code example, you can easily see what is missing and where you go wrong.
May help you a bit
.writeLoop2
mov eax,[ebx] ;mov eax start of data block [ebx]
cmp al,&61 ;61hex is "a"
jb dontsub20 ;if its less don't bother because it's a CAPITAL letter
sub al,&20 ;else take off 20 hex
.dontsub20
call "osasci" ;print to screen command. Output the character in eax
inc ebx ;move ebx forward to next character
inc ecx ;ecx is the rolling count
cmp ecx,edx ;when ecx=edx we are at the end of the data block
jb writeLoop2 ;otherwise loop, there are more characters to print
I'm using C and ASM{} in one of our classes in order to complete an assembler project where we have to encrypt an input string, transmit and decrypt it.
The key is loaded into an empty C char array (20 chars long) and is then used later on with the XOR statement to encrypt.
The code to load the address of the array is:
lea esi, key
which puts the address of 'key' into esi. The address here is the same as the address of the key array when we examine the register in debug mode, so we know that works.
mov edx, [esi]
we thought this would move the value of esi's first index into edx, as we use "mov [esi], eax" to put the value of the a register into the esi array. The reverse seemed logical.
However, the value which edx actually gets is "875575655" (last run) or similar. Far too large for a char value.
I get the feeling we may be accessing the array wrong,
Any advice would be appreciated.
Note: Usually to increase the array index we're simply using inc esi and then read like we did above, this is how we were planning on reading from the array as well.
With mov edx, [esi] you read DWORD (because edx size is double word). Use mov dl, [esi] to read byte.
875575655 in hexa is 0x34303967, that would be string 'g904'.
To explain: while logically it's a character string, you can load more characters at once. So, instead of making 20 byte loads and xors, you can make 5 such operations on DWORD.