data segment
arr dw 20 dup (0001011000000100b), 5 dup (?),
10 dup (0000000010011110b), 11 dup (0000010000001011b), 4 dup (101001b)
num_el dw 50
sum dw 0
mask_2 dw 0000000000000100b
mask_10 dw 0000010000000000b
data ends
code segment
assume cs:code, ds:data
start:
mov ax, data
mov ds, ax
mov cx, num_el
xor ax, ax
xor dx, dx
xor bx, bx
lea si, arr
cycle:
mov ax, [si]
mov dx, [si]
mov bx, [si]
and ax, mask_2
and dx, mask_10
shr dx, 8
cmp ax, dx
je equal
add sum, bx
equal:
add si, 2
loop cycle
mov ah, 4Ch
int 21h
code ends
end start
Вызов процедуры с передачей параметров через стэк (ассемблер)
Задача:
Задан массив А из N = 50 элементов (констант типа WORD).
Определить сумму элементов массива А , для которых биты 2 и 10
не совпадают .
Решение задачи, позитивно оцененное преподавателем:
Код:
Необходимо разработать на языке ассемблера и отладить программу, содержащую главную подпрограмму и вызываемую иэ нее процедуру, которые находятся в отдельных кодовых сегментах разных исходных модулей (файлов). Взаимодействие между ними по данным осуществить путем передачи адресов параметров через стек. Данные и стек определите в отдельных сегментах в исходном модуле, где находится главная подпрограмма. Занесение адресов параметров в стек реализовать в вызывающей последовательности в главной подпрограмме. В вызываемой процедуре осуществить выполнение
индивидуального задания (приведено выше).
Мой вариант реализации:
lb6_1.asm
Код:
data segment
arr dw 20 dup (1011000000100b), 5 dup (?), 10 dup (10011110b), 11 dup (10000001011b), 4 dup (101001b)
num_el dw 50
sum dw 0
data ends
stak segment stack
dw 100 dup (?)
tos label word
stak ends
code segment
extrn procedure:far
assume cs:code, ds:data, ss:stak
start:
mov ax, data
mov ds, ax
mov ax, stak
mov ss, ax
mov sp, offset tos
mov ax, offset num_el
push ax
mov ax, offset sum
push ax
mov ax, offset arr
push ax
call far ptr procedure
mov ah, 4Ch
int 21h
code ends
end start
arr dw 20 dup (1011000000100b), 5 dup (?), 10 dup (10011110b), 11 dup (10000001011b), 4 dup (101001b)
num_el dw 50
sum dw 0
data ends
stak segment stack
dw 100 dup (?)
tos label word
stak ends
code segment
extrn procedure:far
assume cs:code, ds:data, ss:stak
start:
mov ax, data
mov ds, ax
mov ax, stak
mov ss, ax
mov sp, offset tos
mov ax, offset num_el
push ax
mov ax, offset sum
push ax
mov ax, offset arr
push ax
call far ptr procedure
mov ah, 4Ch
int 21h
code ends
end start
lb6_2.asm
Код:
code_procedure segment
public procedure
mask_2 dw 100b
mask_10 dw 10000000000b
summa dw 0
assume cs:code_procedure
procedure proc far
push bp
mov bp, sp
push ax
push bx
push cx
push dx
push si
mov si, [bp+10] ; addr num_el
mov cx, [si]
mov si, [bp+8] ; addr sum
push word ptr [si]
pop summa
mov si, [bp+6] ; addr arr
cycle:
mov ax, [si]
mov dx, [si]
mov bx, [si]
and ax, mask_2
and dx, mask_10
shr dx, 8
cmp ax, dx
je equal
add summa, bx
equal:
add si, 2
loop cycle
mov si, [bp+8]
push summa
pop word ptr [si]
pop si
pop dx
pop cx
pop bx
pop ax
pop bp
retf
procedure endp
code_procedure ends
end
public procedure
mask_2 dw 100b
mask_10 dw 10000000000b
summa dw 0
assume cs:code_procedure
procedure proc far
push bp
mov bp, sp
push ax
push bx
push cx
push dx
push si
mov si, [bp+10] ; addr num_el
mov cx, [si]
mov si, [bp+8] ; addr sum
push word ptr [si]
pop summa
mov si, [bp+6] ; addr arr
cycle:
mov ax, [si]
mov dx, [si]
mov bx, [si]
and ax, mask_2
and dx, mask_10
shr dx, 8
cmp ax, dx
je equal
add summa, bx
equal:
add si, 2
loop cycle
mov si, [bp+8]
push summa
pop word ptr [si]
pop si
pop dx
pop cx
pop bx
pop ax
pop bp
retf
procedure endp
code_procedure ends
end
Программа успешно ассемблируется с использованием tasm 5. Результат выполнения неверен (должен быть 32А5). Путём отладки в турбо-дебаггере ошибочный фрагмент был найден. Во время входа в процедуру значения mask_2 и mask_10 отличаются от заданных. Всё остальное работает верно. Откуда взялась ошибка и как её исправить?
Цитата:
Код:
code_procedure segment
public procedure
mask_2 dw 100b
mask_10 dw 10000000000b
summa dw 0
assume cs:code_procedure
. . . . .
public procedure
mask_2 dw 100b
mask_10 dw 10000000000b
summa dw 0
assume cs:code_procedure
. . . . .
Т.е. у тебя mask_2 и mask_10 хранится внутри code_procedure segment
Обращаешься ты к ним чезез имя переменной, т.е. через указатель.
Цитата:
and ax, mask_2
and dx, mask_10
and dx, mask_10
имхо, это аналогично такому коду:
Код:
and ax, [ offset mask_2] ; доступ к переменной происходи через ее адрес
and dx, [ offset mask_10]
and dx, [ offset mask_10]
При этом обращение к переменной должно выглядеть таким образом:
Код:
mask_2 = [ code_procedure(сегмент) : ХХХХ(смещение) ]
...
and ax,[code_procedure:XXXX]
...
...
and ax,[code_procedure:XXXX]
...
А компилятор-то по умолчанию обращается вот так! :
Код:
mask_2 = [ds:XXXX]
; В твоем случае ds указывает на data segment, тогда:
mask_2 = [ data(сегмент) : XXXX(смещение) ]
...
and ax,[data:XXXX]
; В твоем случае ds указывает на data segment, тогда:
mask_2 = [ data(сегмент) : XXXX(смещение) ]
...
and ax,[data:XXXX]
А [data:XXXX] [code_procedure:XXXX] -- это две разные переменные, расположеные по двум разным адресам. Отсюда и ошибка.
Оказывается, при чтении значений mask_* из памяти компилятор по причине отсутствия телепатических возможностей обращается не к тому сегменту, к которому ты хочешь, чтобы он обратился, а к сегменту, указаному в регистре DS.
Мой вариант решения проблемы:
Код:
procedure proc far
. . . (старый код) . . .
[INDENT]mov di,code_procedure ; в di адрес c_p (просто вынес за границы цикла)[/INDENT]cycle:[INDENT]mov ax, [si] ; тут еще данные хранятся в сегменте data
mov dx, [si]
mov bx, [si]
; а тут уже в сегменте code_procedure
push ds ; сохраняем адрес data segment в стеке
; mov ds,cs или mov ds,cope_procedure -- так нельзя (проверил)
mov ds,di ; так можно (тоже проверил)
and ax, mask_2
and dx, mask_10
; code_procedure segment в DS больше не нужен
pop ds
; адрес data segment восстановлен из стека
. . . ( дальше старый текст ) . . .
[/INDENT]
. . . (старый код) . . .
[INDENT]mov di,code_procedure ; в di адрес c_p (просто вынес за границы цикла)[/INDENT]cycle:[INDENT]mov ax, [si] ; тут еще данные хранятся в сегменте data
mov dx, [si]
mov bx, [si]
; а тут уже в сегменте code_procedure
push ds ; сохраняем адрес data segment в стеке
; mov ds,cs или mov ds,cope_procedure -- так нельзя (проверил)
mov ds,di ; так можно (тоже проверил)
and ax, mask_2
and dx, mask_10
; code_procedure segment в DS больше не нужен
pop ds
; адрес data segment восстановлен из стека
. . . ( дальше старый текст ) . . .
[/INDENT]
Работоспособность не проверял, но думаю, что должно работать, т.к. изменение текста исходной процедуры (той, что одобрена преподавателем:) ) минимальные.
А вот работа со стеком внутри цикла скажется на скорости выполнения программы.
P.S. Пол-шестого. РГЗ по ТЭМЦ рулит!!! :) :) :)
Как ни странно, результат работы программы всё равно неверен. Абсолютно никаких изменений, та же проблема.
попробуйте
mov di,code_procedure
mov es,di
and ax,es:mask_2
или там тоже самое используя регистр ds но поменяйте assume тогда
;вообще это то же самое что уже предложили - но раз mask_2 mask_10 заранее знаете не проще ли использовать define
Спасибо, Витёк! Я понял, в чём проблема.
nilbog
Огромное спасибо, ваша правка
Код:
mov di,code_procedure
mov es,di
and ax,es:mask_2
mov es,di
and ax,es:mask_2
отлично поправила положение дел. Программа работает правильно.
Спасибо за помощь!