Консультация № 186394
19.06.2012, 22:24
149.51 руб.
0 12 1
Уважаемые эксперты! Пожалуйста, ответьте на вопрос:
Задание 4. Изучить особенности сложения и вычитания целых чисел в ПК (беззнаковых и со знаком). Разобраться, для чего служат флаги переноса (CF) и переполнения мантиссы (OF). Изучить команды сложения и вычитания, допустимые типы операндов, устанавливаемые флаги.
Написать фрагмент программы на ассемблере (описание переменных и команды вычислений) в соответствии с указанным вариантом из табл. 5. Подобрать числовые значения таким образом, чтобы команды устанавливали различные флаги условий (OF,CF,ZF,SF); в каждом варианте – по крайней мере 3 различных флага. В комментариях к командам указать получаемые значения флагов.

Вариант задания

F – массив 5 слов. Вычтите из среднего числа сумму остальных. Результат поместить в ВX.


Задание 5. Написать фрагмент программы на ассемблере (описание переменных и команды вычислений) в соответствии с указанным вариантом. Использовать операторы организации цикла и индексирование.

Вариант задания

В последовательные 10 байт памяти поместить коды цифр от ‘0’ до ‘9’. Выполнить размещение не в директиве описания данных, а программно.
А так же. Оформить в виде процедур фрагмент программы :
1. С передачей параметров через регистры.
2. Через стек.


Приложение:
Пример для задания 4
; Несколько примеров на пересылки и арифметику
; Сегмент данных отсутствует за ненадобностью

S SEGMENT STACK
DW 64 DUP(?)
S ENDS

C SEGMENT
ASSUME SS:S,CS:C,DS:NOTHING

Start PROC FAR
; Выполнение соглашений DOS и настройка регистра DS
PUSH DS
SUB AX,AX
PUSH AX

; сложение - вычитание
; пример сложения-вычитания без "особенностей"
mov ax, 32
add ax, 32
mov bx, 16
sub ax, bx
sub ax, bx

; переполнение при сложении
sub ax, ax ; очистить ax. Установится флаг ZF!
mov al, 7Ch ; 124, 01111100 - почти максимальное положительное число
add al, 3 ; 127, 01111111 - ни переноса, ни переполнения
add al, 2 ; =129 беззнаковое, =-127 знаковое, 10000001 - переполнение (OF!, SF!)
; перенос при сложении
mov ah, 0FAh ; пересылки значений флагов не меняют
add ah, 3 ; SF! (старший бит - 1)
add ah, 3 ; CF! (сумма не поместилась в 8 бит) ZF (0 получается!)
; перенос при вычитании
; 12-13 = -1
mov cx, 12
sub cx, 1 ; сбросили все флаги (не 0, положит, переноса и переполнения нет)
sub cx, 13 ; CF! и SF! (старший бит - 1)
; переполнение при вычитании
; 127 - (-3) = 130, в 7 битах не поместится и окажется -126-ью
sub dx, dx
sub cx, cx
mov dl, 127
mov cl, -3
sub dl, cl ; OF! CF! SF! (127-253, если рассматривать как беззнаковое)

; Возврат в DOS
RET

Start ENDP
C ENDS
END Start

Обсуждение

Неизвестный
20.06.2012, 04:48
общий
Здравствуйте! Отправляю решение пункта №4 - где массив из пяти слов:

; ***** Задание № 4 ****** ВЫЧИТАНИЕ ИЗ СРЕДНЕГО ЭЛЕМЕНТА МАССИВА
; сегмент стека
ssg segment stack 'stack'
db 100h dup(?)
ssg ends

; сегмент данных
dsg segment 'data'
mas_ dw 123,-200,45,789,-442 ; массив из пяти значений размером в слово
dsg ends

; сегмент кода
csg segment 'code'
assume ss:ssg,cs:csg,ds:dsg

main proc near; основная процедура программы
; настройка сегментного регистра данных
mov ax, dsg
mov ds, ax

lea si,mas_ ; получаем адрес первого элемента массива
mov bx,word ptr [si+4] ; в bx заносим значение среднего элемента, 3-го
; для этого смещаемся на 2 элемента (4 байта)
xor dl,dl ; обнуляем dl
sub si,2 ; уменьшаем si на 2
mov cx,4 ; счетчик цикла
; смысл цикла такой - прогоняем массив и каждый
; элемент вычитаем из bx - если встречаем средний (dl=2)
; то пропускаем
for_:
cmp dl,2 ; сравниваем dl со значением 2
pushf ; сохраняем регистр флагов в стеке
inc dl ; увеличиваем dl на 1
add si,2 ; прибавляем к si 2
popf ; восстанавливаем регистр флагов из стека
je for_ ; если dl = 2 - то переходим сразу на метку for_
sub bx,word ptr [si] ; вычитаем из значения в bx значение
; очередного элемента массива
loop for_ ; переход на метку for_ и уменьшение cx на 1
; если cx = 0, то происходит выход из цикла

; в этом месте значение регистра bx должно быть требуемым
; можно посмотреть через отладчик или воспользоваться
; процедурой код, которой в самом низу
mov si,bx ; заносим в si - то что хотим посмотреть
call out_num ; вызываем процедуру вывода на экран
; код процедуры без комментариев, так как не
; относится к задаче, а добавлена лишь для проверки

; ожидание нажатия клавиши
mov ah,10h
int 16h

; выход в DOS
mov ax,4c00h
int 21h
main endp

; начало процедуры вывода на экран
out_num proc near
cmp si,0
jge lab0
mov ah,02h
mov dl,'-'
int 21h
mov ax,si
mov bx,-1
imul bx
mov si,ax

lab0:
mov cx,0
mov ax,si
mov bx,10
lab1:
inc cx
mov dx,0
idiv bx
cmp ax,0
jne lab1

mov ax,si
lab2:
mov bx,1
cmp cx,1
je lab4
push cx
push ax
dec cx
mov bx,10
mov ax,1
lab3:
imul bx
loop lab3
mov bx,ax
pop ax
pop cx
lab4:
mov dx,0
idiv bx
push dx
mov ah,02h
mov dl,al
add dl,'0'
int 21h
pop ax
loop lab2
ret
out_num endp
; окончание процедуры вывода на экран

csg ends
end main
Неизвестный
20.06.2012, 04:51
общий
Отправляю решение пункта №5:

; ***** Задание № 5 ******
; сегмент стека
ssg segment stack 'stack'
db 100h dup(?)
ssg ends

; сегмент данных
dsg segment 'data'
str_ db 10 dup(?) ; область в 10 байт для размещения символов цифр
s_ db 13,10,'$' ; после ставим символы для перевода строки и $ -
; чтобы вывести строку на экран
; для проверки - $ - признак окончания строки
dsg ends

; сегмент кода
csg segment 'code'
assume ss:ssg,cs:csg,ds:dsg

main proc near; основная процедура программы
; настройка сегментного регистра данных
mov ax, dsg
mov ds, ax

; заносим цифры от '0' до '9'
mov cx,10 ; счетчик цикла
lea bx,str_ ; получаем адрес первого байта str_
xor si,si ; si = 0
for_: ; метка начала цикла
mov ax,si ; заносим в ax текущее значение si
add ax,'0' ; прибавляем код символа '0' - это 48, чтобы из цифры
; получить символ цифры
mov [bx+si],al ; заносим по адресу в очередной байт строки цифру (ее код)
inc si ; увеличиваем si на 1
loop for_ ; переход на метку for_ и уменьшение cx на 1
; если cx = 0, то происходит выход из цикла

; передача параметра через стек
lea bx,str_ ; получаем адрес первого байта строки для вывода на экран
push bx ; заносим в стек
call proc1 ; вызываем процедуру

; передача параметра через регистр
lea ax,str_ ; получаем адрес первого байта строки для вывода на экран
call proc2 ; вызываем процедуру

; ожидание нажатия клавиши
mov ah,10h
int 16h

; выход в DOS
mov ax,4c00h
int 21h
main endp

; процедура получения параметра через стек
proc1 proc near
; эти две строки называются прологом
push bp ; сохраняем в стеке регистр bp - так как мы его будем менять
mov bp,sp ; в bp помещаем адрес из sp - адрес верхушки стека

mov dx,word ptr [bp-2] ; получаем параметр из стека в регистр dx, bp - на самом
; верху стека у нас значение регистра bp - поэтому берем
; отступ в два байта и получаем наш параметр
; выводим строку на экран при помощи сервисного прерывания 21h
mov ah,09h
int 21h

; эти две строки называются эпилогом
mov sp,bp ; восстанавливаем sp
pop bp ; восстанавливаем bp

retn 2 ; снимаем с верхушки стека 2 байта - размер передаваемых параметров
proc1 endp

; процедура получения параметра через регистр
proc2 proc near
mov dx,ax ; получаем параметр переданный через регистр ax
; выводим строку на экран при помощи сервисного прерывания 21h
mov ah,09h
int 21h
ret ; при передаче параметра через регистр ничего снимать не нужно
; с верхушки стека
proc2 endp

csg ends
end main
Неизвестный
20.06.2012, 04:53
общий
По поводу самого начала просьба уточнить: необходимо привести примеры изменения флагов (OF,CF,ZF,SF) и в тоже время вы уже сами привели пример этого. Или как-то по другому нужно сделать?
давно
Посетитель
7438
7205
20.06.2012, 11:42
общий
это ответ
Здравствуйте, Igordrum!
4)
[code h=200];Краткая справка по необходимым флагам
;OF — флаг переполнения. Этот флаг устанавливается в 1, если результат предыдущей
; арифметической операции над числами со знаком выходит за допустимые для них пределы.
; Например, если при сложении двух положительных чисел получается число со старшим битом,
; равным единице (то есть отрицательное) и наоборот.
;CF — флаг переноса. Устанавливается в 1, если результат предыдущей операции
; не уместился в приемнике и произошел перенос из старшего бита или если
; требуется заем (при вычитании), иначе устанавливается в 0.
; Например, после сложения слова 0FFFFh и 1, если регистр, в который надо
; поместить результат, — слово, в него будет записано 0000h и флаг CF = 1.
;ZF — флаг нуля. Устанавливается в 1, если результат предыдущей команды — ноль.
;SF — флаг знака. Этот флаг всегда равен старшему биту результата.

;F – массив 5 слов. Вычтите из среднего числа сумму остальных.
;Результат поместить в ВX

SSEG SEGMENT STACK
DW 64 DUP(?)
SSEG ENDS

DSEG SEGMENT ; сегмент данных
; ДИРЕКТИВЫ ОПИСАНИЯ ДАННЫХ
F DW 0002h,7fffh,0ffffh,8000h,0fffeh
DSEG ENDS
CSEG SEGMENT
ASSUME SS:SSEG,CS:CSEG,DS:DSEG

Start PROC FAR
; Выполнение соглашений DOS и настройка регистра DS
PUSH DS
SUB AX,AX
PUSH AX
MOV AX,DSEG
MOV DS,AX

MOV AX,F ; AX = 0002h
ADD AX,F+2 ; AX = 0002h+07fffh = 8001h
; O=1, S=1, Z=0, C=0
ADD AX,F+6 ; AX = 8001h+8000h = 0001h
; O=1, S=0, Z=0, C=1
ADD AX,F+8 ; AX = 0001h+0fffeh = 0ffffh
; O=0, S=1, Z=0, C=0
MOV BX,F+4 ; BX = 0ffffh
SUB BX,AX ; BX = 0ffffh - 0ffffh = 0
; O=0, S=0, Z=1, C=0
; Возврат в DOS
RET

Start ENDP
CSEG ENDS
END Start[/code]
5)
[code h=200];В последовательные 10 байт памяти поместить коды цифр от ‘0’ до ‘9’.
;Выполнить размещение не в директиве описания данных, а программно.

SSEG SEGMENT STACK
DW 64 DUP(?)
SSEG ENDS

COUNT EQU 10

DSEG SEGMENT ; сегмент данных
NUMS DB COUNT dup(?)
DSEG ENDS

.186
CSEG SEGMENT
ASSUME SS:SSEG,CS:CSEG,DS:DSEG

Start PROC FAR
; Выполнение соглашений DOS и настройка регистра DS
PUSH DS
SUB AX,AX
PUSH AX
MOV AX,DSEG
MOV DS,AX

LEA SI,NUMS
MOV CX,COUNT
MOV AL,'0'
FORM_NUM_LOOP:
MOV [si],AL
INC SI
INC AL
LOOP FORM_NUM_LOOP

RET
Start ENDP

CSEG ENDS
END Start[/code]
В виде процедур:
[code h=200];В последовательные 10 байт памяти поместить коды цифр от ‘0’ до ‘9’.
;Выполнить размещение не в директиве описания данных, а программно.

SSEG SEGMENT STACK
DW 64 DUP(?)
SSEG ENDS

COUNT EQU 10

DSEG SEGMENT ; сегмент данных
NUMS DB COUNT dup(?)
DSEG ENDS

.186 ;необходимо, чтобы в стек засылать число
CSEG SEGMENT
ASSUME SS:SSEG,CS:CSEG,DS:DSEG

Start PROC FAR
; Выполнение соглашений DOS и настройка регистра DS
PUSH DS
SUB AX,AX
PUSH AX
MOV AX,DSEG
MOV DS,AX

LEA SI,NUMS ;в регистрах
MOV CX,COUNT
CALL FORM1

PUSH OFFSET NUMS;через стек
PUSH COUNT
CALL FORM2

RET
Start ENDP

FORM1 PROC
MOV AL,'0'
FORM_NUM_LOOP1:
MOV [SI],AL
INC SI
INC AL
LOOP FORM_NUM_LOOP1
RET
FORM1 ENDP

FORM2 PROC
PUSH BP ;сохраним старое значение BP
MOV BP, SP ;будем адресовать стековый кадр

MOV CX, [BP+4] ;длина массива
MOV SI, [BP+6] ;адрес массива

MOV AL,'0'
FORM_NUM_LOOP2:
MOV [SI],AL
INC SI
INC AL
LOOP FORM_NUM_LOOP2

POP BP ;восстановим старый BP
RET 4 ;при возврате удалим из стека 4 байта (2 слова)!
FORM2 ENDP

CSEG ENDS
END Start[/code]
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
20.06.2012, 12:10
общий
Здравствуйте, Дмитрий!
1) "примеры изменения флагов (OF,CF,ZF,SF)" необходимо сделать для указанной задачи,
причем указать, как эти флаги меняются! Приведенная программа выполняет другую задачу!
2) Вывод совершенно не нужен! Стоит задача всего лишь "написать фрагмент программы" и "разобраться, для чего служат флаги"... Читайте внимательно условие задачи!
3) Во второй программе необходимо было одну и ту же подпрограмму оформить как с передачей параметра чере регистры, так и через стек.
4) Вывод также не нужен! Не надо нагромождать программу лишними операциями. Стоит задача разобраться в передаче параметров.

Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
20.06.2012, 12:19
общий
Адресаты:
Добрый день! Ясно, понял. А ответы давать у меня возможности нет? Или они как-то даются через обычные сообщения?
Неизвестный
20.06.2012, 12:21
общий
Адресаты:
Или лучше не мешать?
давно
Посетитель
7438
7205
20.06.2012, 12:43
общий
20.06.2012, 12:45
Во-первых, возможность отвечать у Вас нет только на этот вопрос по одной простой причине: Вы стали экспертом в данной рассылке позже того, как вопрос появился. На все последующие вопросы Вы отвечать сможете.
Во-вторых, отвечайте, я только рад новым лицам. Но отвечайте правильно! Я очень ревностно отношусь к ответам в рассылке по Ассемблеру, хочу, чтобы ответы были на самом высоком уровне. (Ну фишка у меня такая, неравнодушен я к нему )
Так что учтите, у Вас очень строгий судья
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
20.06.2012, 12:56
общий
Кстати, дарю процедуру вывода знакового числа из регистра AX
Код:
PrintNum	proc		; вывод числа из AX
test ax, ax ;проверим на знак
jns form_str ;для положительного на вывод
push ax ;для отрицательного выводим - и меняем знак
mov al,'-' ;знак -
int 29h
pop ax
neg ax ;меняем знак числа на +, теперь оно положительное

form_str:
mov bx, 10 ; будем делить на 10
xor cx, cx ; счетчик цифр
div_loop: ; цикл получения десятичных разрядов
xor dx, dx ; подготовимся для очередного деления
div bx ; в dx остаток - очередной десятичный разряд
push dx ; сохраним в стеке (от младшего к старшему)
inc cx ; посчитаем
test ax, ax ; есть еще десятичные разряды?
jnz div_loop ; продолжим

pr_loop: ; цикл вывода десятичных цифр-символов
pop ax ; востановим очередной разряд (от старшего к младшему)
add al, '0' ; символ цифры
int 29h ; вывод
loop pr_loop ; по всем цифрам
ret
PrintNum endp
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
20.06.2012, 12:57
общий
Адресаты:
Мне тоже ассемблер нравится, хотя современные программисты считают, что он устарел. А у меня наоборот интерес к нему все больше и больше. Стремление заниматься например только C# - скрывает понимание многих вещей и квалификация у программиста уже не та. Хорошо, буду ответы делать минимально краткими. В крайнем случае сделаю свой сайт - и буду сам там старшим модератором
Неизвестный
20.06.2012, 13:03
общий
Адресаты:
Спасибо за процедуру, я знал, что можно все короче написать Для заказчика - это конечно правильнее. А для себя - я все сам пишу - сначала смысл посмотрю посмотрю, а потом с нуля напишу. Так приходит хорошее понимание. Мне и тот эксплойт для IE8 нужно самому с нуля написать, тогда я смогу сказать, что я в нем разобрался. Я поэтому и задал вопрос, что мне нужно понимать просчет нужных мест оперативной памяти для подмены адресов перехода, но в WinAPI и защищенном режиме пока не много опыта.
давно
Посетитель
7438
7205
20.06.2012, 13:07
общий
Ответы должны быть максимально информативными, т.е. отвечать на поставленный вопрос.
И в то же время, без "воды", чтобы не отвлекать внимание.
Мне Ассемблер не просто нравится, я по уши влюблен, причем сразу и с самого начала, с момента появления РС на x86...
Что ж, буду рад наблюдать за Вашими ответами...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Форма ответа