I am new to assembly programming and trying to write a simple assembly level code where the intention is to send the base address of an array to a stack and access it within a procedure to find out the smallest element The array is a 5 byte array with 5 elements. Unfortunately after passing the address of the array within stack I am unable to access it back through BP register. The code snippet is as below and I am using the 8086 emulator. Any help will be very much appreciated.
START:
MOV AX,#data
MOV DS,AX
;MOV AX,STACK
;MOV SS,AX
;MOV SP,OFFSET TOP_STACK
MOV BX,OFFSET ARRAY
PUSH BX
PUSH BP
MOV BP,SP
MOV BX,[BP+4]
MOV AX,[BX]
Till the second last line I am able to follow the execution and the system is showing the correct address of the data segment. However when the last line executes I expect that the first element of the array will be available ( i.e 10 ) but in reality I get only 0.
Here is the full code:
.stack 100h
.data
ARRAY DB 10H,05H,20H,60H,35H
.code
START:
MOV AX,#data
MOV DS,AX
MOV BX,OFFSET ARRAY
PUSH BX
PUSH BP
CALL PROC1 ; CALLING POINT OF THE PROCEDURE
MOV AH,4CH
INT 21H
PROC1 PROC NEAR
MOV BP,SP
MOV BX,word[BP+3] ; ARRAY BASE ADDRESS
XOR AX,AX
MOV AL,BYTE[BX]
MOV CX,04
SMALL:
MOV AH,BYTE[BX]
CMP AL,AH
JG SWAP
INC BX
LOOP SMALL
JMP EXITPROC
SWAP:
MOV AL,AH
INC BX
JMP SMALL
EXITPROC:
POP BP
POP BX
RET
PROC1 ENDP
CODE ENDS
END START
Related
I want to sort an array while using the stack:
so first things first I pushed it all into the stack.
then I'm locating the minimum element in the stack, swapping it with the top element popping it out and move it back to the array.
but something isn't right and about halfway there it got messed up (DI is one index below than what it should really be)
data segment
a db 5h,12h,6h,4h,9h
len equ $-a
loop_counter db len
min_index dw 0
min db ?
ends
stack segment
dw 128 dup(0)
ends
code segment ;TODO: Locate min in stack xchg it with top element copy to array and pop it :|
start:
mov ax, data
mov ds, ax
mov bx,0
mov cx,0
mov cl,loop_counter
push_arr_to_stack:
mov al,a[bx]
push ax
inc bx
loop push_arr_to_stack
mov bx,len-1
mov ax,0
mov cl,loop_counter
mov bp,sp
mov ax,[bp]
mov bx,[bp]
mov di,0
mov dx,0
mov si,2
mov di_check,len-loop_counter
find_min_to_arr:
cmp bx,ax
jb new_min
mov bx,[bp+si]
add si,2
loop find_min_to_arr
mov min,al
xchg a[di],al
jmp pop_min
new_min:
mov ax,bx
mov bx,[bp+si]
mov min_index,si
sub min_index,2
add si,2
dec cx
jmp find_min_to_arr
pop_min:
mov dx,[bp]
xchg di,min_index
mov [bp+di],dx
xchg di,min_index
pop dx
mov dx,0
inc di
mov si,0
cmp di,len
je b
dec loop_counter
mov cl,loop_counter
jmp find_min_to_arr
b:
mov ax, 4c00h ; exit to operating system.
int 21h
ends
end start
first I pushed it all into the stack.
This part is fine although for speed reasons you should forget about loop .. and replace it with dec cx followed by jnz ..
then I'm locating the minimum element in the stack, swapping it with the top element popping it out and move it back to the array.
Here your code gets very complicated and it contains many errors. Also the code does not perform true swapping between the located minimum and the element at the top of the stack.
I tried amending your code but as is often the case, it is beyond repair. Below is my rewrite that you should study, not just copy!
I have defined the loop_counter a word variable because that's easier. Additionally I kept it in the DX register that was sitting there doing nothing...
Pushing it all into the stack
mov bx, dx
push_arr_to_stack:
mov al, a[bx-1]
push ax
dec bx
jnz push_arr_to_stack
I push the array in reverse so the stack has the elements in the same order as the original array. This is not necessary for the task, but it is simpler and it leaves the BX register at zero for use below.
Locating the minimum in the stack
Again:
mov bp, sp
xor si, si
mov al, [bp+si] ; Chosen minimum
mov di, si ; Remember its position
mov cx, dx
dec cx ; N elements = N-1 compares
jz .c
.a: add si, 2
cmp al, [bp+si]
jbe .b
mov al, [bp+si] ; New minimum
mov di, si ; Remember its position
.b: dec cx
jnz .a
Swapping it with the top element
.c: xchg al, [bp]
mov [bp+di], al
Popping it out and moving it back to the array
pop ax
mov a[bx], al
inc bx
dec dx
jnz Again
The important thing here is that the above exactly does what the task description said.
I'm trying to sort an array using the registers from biggest to least and nothing seems to be working. The ecx is my amount of numbers that I have, the esi is the address of my list which consists of dwords. I use the edx to keep going up by 4 bytes to each element. My code doesn't sort the entire array I know that I need to find the location of the max and then set it equal to the outer loops edx but I can't seem to figure out how to change the elements in the array because I only have the edx register. I tried pushing the location and then popping it back out when the inner loop was finished but that didn't seem to work. Please anything is appreciated I have been working on this problem for over 4 hours.
push ebp
mov ebp,esp
mov ecx,[ebp+8]
mov esi,[ebp+12]
mov edx,-4
outerloop:
add edx,4
push edx
push ecx
mov ebx,[edx+esi]
innerloop:
add edx,4
mov eax,[edx+esi]
cmp ebx,eax
jl change
finish:
loop innerloop
pop ecx
pop edx
loop outerloop
jmp done
change:
mov [edx+esi],ebx
mov [edx+esi-4],eax
sub edx,4
push edx
mov edx,offset change1
call writestring
pop edx
jmp finish
done:
pop ebp
ret 8
What you are looking for is a 'reversed' Bubble Sort (You can of course use any sorting algorithm you wish, but this is simple for an example). I'm not sure what assembler you're using, but here's a short assembly function that will accomplish a sort of n int32_t integers stored in array/list arr. (This example was written in NASM)
;int *sort(int *arr,int n);
sort:
push ebp
mov ebp,esp
mov edx,[ebp+12]
.loop1:
mov esi,[ebp+8] ;arr ptr
mov ecx,[ebp+12] ;n number of ints
.loop2:
mov eax,[esi] ;compare
mov ebx,[esi+4]
cmp eax,ebx
jg .skip
mov [esi],ebx ;swap
mov [esi+4],eax
.skip:
add esi,4 ;perform loop checks
dec ecx
cmp ecx,1
ja .loop2
dec edx
ja .loop1
mov eax,[ebp+8] ;return arr
mov esp,ebp
pop ebp
ret
Please keep in mind this example wasn't really optimized (e.g., it iterates too many times through the whole array). Sometimes (esp. in assembly languages), less is more. Instead of offsetting the pointer by ecx/edx, you can increment the array pointer (or a copy of it), and do comparisons using that directly. This way you don't have to keep track of a counter register AND the pointer at the same time. :)
The following code is supposed to add two one-dimensional matrices and display the sum. There is a problem when the program takes the inputs for the second matrix: the rd_next loop never ends. However it takes the inputs for the first matrix just fine.
data_seg segment
mat1 dw 3 dup(?)
mat2 dw 3 dup(?)
n db 3
ten dw 10
counter db ?
string db 10 dup(?)
msg1 db 10,13,"Enter first matrix: ","$"
msg2 db 10,13,"Enter second matrix: ","$"
msg3 db 10,13,"Enter a number: ","$"
data_seg ends
code_seg segment
assume cs:code_seg,ds:data_seg
print_string proc
pop si
pop dx
mov ah,9
int 21h
push si
ret
print_string endp
read_char proc
pop di
mov ah,1
int 21h
mov ah,0
push ax
push di
ret
read_char endp
read_number proc
pop si
mov bx,0
mov dx,0
next_digit:
call read_char
pop ax
cmp al,0Dh
je done
sub al,30h
mov cl,al
mov ch,0
mov ax,bx
mul ten
add ax,cx
mov bx,ax
jmp next_digit
done: push bx
push si
ret
read_number endp
print_number proc
pop si
pop ax
mov bx,0
mov dx,0
repeat1:
mov cx,0
mov dx,0
div ten
push dx
inc counter
cmp ax,0
jne repeat1
print_digit:
pop dx
add dl,30h
mov ah,2
int 21h
dec counter
jnz print_digit
push si
ret
print_number endp
start:
mov ax,data_seg
mov ds,ax
mov al,n
mov counter,al ; initialize counter variable
mov bp,offset mat1 ; initialize pointer to first matrix
push offset msg1 ; prompt user to enter first matrix
call print_string
rd_next:
push offset msg3 ; prompt user for next number in matrix
call print_string
call read_number ; call the read_number procedure.
pop dx
mov [bp],dx
add bp,2
dec counter
jnz rd_next ; loop back to read the next number.
mov counter,al ; reset counter variable
mov bp,offset mat2 ; initialize pointer to second matrix
push offset msg2 ; prompt user to enter second matrix
call print_string
jmp rd_next
mov al,n
mov si,offset mat1
mov di,offset mat2
matrixsum:
mov bx,[si]
mov cx,[di]
add bx,cx
push bx
call print_number
inc si
inc di
dec al
jnz matrixsum
code_seg ends
end start
I don't see anything wrong with the code. I tried creating a separate rd_next2 loop for taking the inputs for the second matrix but it does not work.
Oh it will end all right, just takes some time, since you forgot to re-initialize counter. Move the initialization code inside the rd_next, e.g.:
mov bp,offset mat1 ; initialize pointer to first matrix
push offset msg1 ; prompt user to enter first matrix
call print_string
rd_next:
mov al,n
mov counter,al ; initialize counter variable
Learn to use a debugger so you can single step your code and see why it is doing what it is.
PS: you have an ingenious way to return result from a function but please don't do that :D Just use a register as everybody else.
8086 assembly language program that sorts an array as follows:
smallest value in the array should be placed in the first cell.
second smallest value in the last cell.
third smallest value in the second cell of the array.
fourth smallest value placed in the before-last cell of the
array.
• The above procedure continues until the array is fully sorted.
Note that in the above-described sorting technique, the large values in the initial array
will end up being placed at the middle part of the array
here is my code it sorting but in normal way :
org 100h
.MODEL SMALL
.DATA
TABLE DB 9,2,6,8,5,1
B DB 6 DUP(0)
VAL1 DB 5
NL DB ' ','$'
.CODE
MOV AX,#DATA
MOV DS,AX
LEA BX,TABLE
MOV DL,VAL1
LBL1:
LEA BX,TABLE
MOV CL,5
LBL2:
MOV AL,[BX]
MOV DL,[BX+1]
CMP AL,DL
JB LBL3
MOV [BX],DL
MOV [BX+1],AL
LBL3:
INC BX
LOOP LBL2
MOV DL,VAL1
DEC DL
MOV VAL1,DL
CMP DL,00
JNE LBL1
MOV CL,6
LEA BX,TABLE
DISPLAY:
LEA DX,NL
MOV AH,09H
INT 21H
MOV DL,[BX]
ADD DL,30H
MOV AH,02H
INT 21H
INC BX
INC BX
LOOP DISPLAY
MOV AH,4CH
INT 21H
ret
Replace:
mov cl, val1
by:
mov cl, [val1]
This way it moves the content of val1 (the number 5) to cl. In the code above, it would only move the offset of val1 to cl (the same as lea cl, val1).
I've written this procedure in asm:
.586
.model flat, stdcall
.xmm
.data
.code
EncryptAsm proc plainText:ptr byte, heigth:DWORD, inputLength:DWORD, encryptedText:ptr byte, cipherArray:ptr byte
local addRow:WORD
local row:DWORD
local column:DWORD
local iterator:DWORD
local forLoopIteratorI:DWORD
local forLoopIteratorJ:DWORD
push esi
push edi
push ebx
push ecx
push edx
mov addRow,0
mov row,0
mov column,0
mov iterator,0
mov forLoopIteratorI,0
mov forLoopIteratorJ,0
mov ecx,heigth
FILL_CIPHER_ARRAY_LOOP: mov eax, inputLength
cmp iterator,eax
jge PREPARE_ITERATOR
push ecx ;pushing heigth value
mov ecx,row ;calculating index of cipher array index=[row*inputLength+column]
imul ecx,inputLength
add ecx,column
mov eax,iterator
mov edx,plainText
mov al,[edx+eax]
mov [esi],al
mov ebx, cipherArray
mov [ebx+ecx],al
movsb
pop ecx;getting back heigth value
add column,1
cmp addRow,0
je INC_ROW
cmp addRow,0
jne DEC_ROW
INC_ROW: add row,1
jmp ROW_COMPARE
DEC_ROW: sub row,1
jmp ROW_COMPARE
ROW_COMPARE: cmp row,ecx
jge IF_STATEMENT_1
cmp row,0
jl IF_STATEMENT_2
jmp INCREMENT_ITERATOR
IF_STATEMENT_1: sub row,2
mov addRow,1
jmp INCREMENT_ITERATOR
IF_STATEMENT_2: add row,2
mov addRow,0
jmp INCREMENT_ITERATOR
INCREMENT_ITERATOR: add iterator,1
jmp FILL_CIPHER_ARRAY_LOOP
PREPARE_ITERATOR: mov iterator,0
READ_CIPHER_ARRY_LOOP_I:cmp forLoopIteratorI,ecx
jge PREPARE_ITERATOR_2
READ_CIPHER_ARRY_LOOP_J:mov eax, inputLength
cmp forLoopIteratorJ,eax
jge PREPARE_I_AND_J
push ecx ;pushing heigth value
mov ecx,forLoopIteratorI ;calculating index of cipher array
imul ecx,inputLength
add ecx,forLoopIteratorJ
mov ebx,cipherArray
mov al,[ebx+ecx]
cmp al,'#'
jne COPY_VALUE
ITERATE: add forLoopIteratorJ,1
pop ecx
jmp READ_CIPHER_ARRY_LOOP_J
PREPARE_I_AND_J: mov forLoopIteratorJ,0
add forLoopIteratorI,1
jmp READ_CIPHER_ARRY_LOOP_I
COPY_VALUE: push edi
mov edi,iterator
mov edx,encryptedText
mov [edx+edi],al
add iterator,1
pop edi
jmp ITERATE
PREPARE_ITERATOR_2: mov iterator,0
FINISH: mov eax, encryptedText
pop edx
pop ecx
pop ebx
pop edi
pop esi
ret
EncryptAsm endp
end
It implements rail fence cipher algorithm (at the end the variable encryptedText contains ciphered plainText). It works fine, I mean it does the encryption well but after all I'm getting memory corrupt error... I'm calling this procedure as an extern one from C app. I can print the encrypted text without any problem but when returning 0 in main function, the memory corrupt error pops up.
I don't know what can cause it. At the beginning of asm procedure, I push all the registers' values and pop them after the whole operation.
The error message:
Unhandled exception at 0x72676F74 in ConsoleApplication12.exe: 0xC0000005: Access violation executing location 0x72676F74.
I'll be greatful for any hint.
One possible candidate could be here:
mov edx,plainText
mov al,[edx+eax]
mov [esi],al
esi is pushed, from the caller, but where is it initialized? It seems that it uses whatever is there from the caller. Same for edi so where will movsb store it?
UPDATE
Since I don't know your algorithm and don't see how it is used I can only guess. BUt I think you should do the following before the loop:
mov esi, plainText
mov edi, encryptedText
mov ebx, cipherArray
Since you don't change these values you can then change this code:
COPY_VALUE: push edi
mov edi,iterator
mov edx,encryptedText
mov [edx+edi],al
add iterator,1
pop edi
jmp ITERATE
to this:
COPY_VALUE: mov edx,iterator
mov [edx+edi],al
inc iterator
jmp ITERATE
Generally instead of using add x, 1 you can use inc x which is shorter.
People I've found it! The cause of the error was... 'movsb'. I was using it in a previous version of my algorithm and I've forgotten to delete it... The rest of my code works fine. Thanks for all the answers and for willing to help m ;)