ret LongShiftRight2 endp
Ассемблер обеспечивает, что инструкция ret будет ближнего типа, так как LongShiftRight2 это процедура ближнего типа (near). Однако, если директиву proc изменить следующим образом:
LongShiftRight2 proc far,
то будет генерироваться инструкция ret дальнего типа (far).
Часто группируют в одной и той же процедуре несколько процедур. Поскольку в этих процедурах отсутствует соответствующая директива proc, их инструкции ret будут иметь тип той процедуры, в которую они заключены, а для конкретных подпрограмм этот тип не всегда может оказаться корректным.
Например:
; Подпрограмма дальнего типа для сдвига dx:ax на 2 бита
LongShiftRight2 proc far |
|
||
call |
LongShiftRight |
; сдвиг dx:ax вправо на 1 бит |
|
call |
LongShiftRight |
; сдвиг dx:ax вправо еще на 1 бит |
|
ret |
|
|
|
LongShiftRight: |
|
|
|
shr |
dx,1 |
|
|
rcr |
ax,1 |
; сдвиг dx:ax вправо на 1 бит |
|
ret |
|
|
|
LongShiftRight2 endp
работает неправильно. Процедура LongShiftRight2 обращается с вызовом ближнего типа к LongShiftRight (так как они находятся в одном сегменте кода). Однако, так как LongShiftRight встроена в процедуру LongShiftRight2, то возврат в конце подпрограммы LongShiftRight становится возвратом дальнего типа, а когда вызову ближнего типа соответствует возврат дальнего типа, это с большой вероятностью может привести к сбою (аварийному завершению программы).
Хорошим решением здесь будет наличие в каждой подпрограмме директивы proc. Вложенные директивы proc прекрасно работают.
; Подпрограмма дальнего типа для сдвига dx:ax на 2 бита.
;
LongShiftRight2 |
proc far |
|
|
call |
LongShiftRight |
; сдвиг dx:ax вправо на 1 бит |
|
call |
LongShiftRight |
; сдвиг dx:ax вправо еще на 1 бит |
|
ret |
|
|
|
LongShiftRight |
proc near |
|
|
shr |
dx,1 |
|
56 |
|
|
|
|
rcr ax,1 |
; сдвиг dx:ax вправо на 1 бит |
ret |
|
LongShiftRight2 |
endp |
LongShiftRight |
endp |
Также, как и последующие процедуры:
; Подпрограмма дальнего типа для сдвига dx:ax на 2 бита.
;
LongShiftRight2 |
proc far |
|
call |
LongShiftRight; сдвиг dx:ax вправо на 1 бит |
|
call |
LongShiftRight; сдвиг dx:ax вправо еще на 1 бит |
|
ret |
|
|
LongShiftRight2 |
endp |
|
LongShiftRight |
proc near |
|
shr |
dx,1 |
|
rcr |
ax,1 ; сдвиг dx:ax вправо на 1 бит |
|
ret |
|
|
LongShiftRight |
endp |
|
Для явной генерации ближнего или дальнего возврата можно использовать соответственно инструкции retn и retf. Вы можете обеспечить с их помощью корректную генерацию инструкций возврата.
7.21. Ошибки при использовании условных переходов
Использование в языке ассемблера инструкций условных переходов (je, jne, jc, jnc, ja, jb, jg и т.д.) обеспечивает большую гибкость в программировании, но при этом очень просто ошибиться, выбрав неверный переход. Типичные ошибки:
7.21.1.Использование инструкций ja, jb, jae или jbe для сравнения значений со знаком или, соответственно, инструкций jg, jl, jge или jle для сравнения беззнаковых значений.
7.21.2.Использование, скажем, инструкции ja там, где нужно использовать jae. Нужно помнить о том, что без буквы e в конце инструкции в сравнении не учитывается случай, когда два операнда равны.
7.21.3.Использование инвертированной логики, например, применение инструкции js там, где нужно использовать jns.
Один из подходов, позволяющий минимизировать ошибки при использовании условных переходов состоит в комментировании
57
переходов в соответствии с обозначениями, аналогичными языку Си. Например:
;
; if { Length > MaxLength } {
;
mov |
ax,[Length] |
cmp |
ax,[MaxLength] |
jng |
LengthIsLessThanMax |
. . . |
|
jng |
EndMaxLengthTest |
; |
|
;} else {
;
LengthIsLessThanMax:
. . .
;
;}
;
EndMaxLengthTest:
7.22. Путают операнды в памяти и непосредственные
Программа на ассемблере может ссылаться либо на переменную памяти по смещению, либо на значение, хранящееся в этой переменной.
Например, смещение переменной в памяти размером в слово MemLoc представляет собой константу 5002, которую можно получить с помощью оператора OFFSET. Например, инструкция
mov bx,OFFSET MemLoc
загружает значение 5002h в регистр bx. Значение 5002h представляет собой непосредственный операнд. Другими словами, оно встроено непосредственно в инструкцию и не изменяется.
Значением MemLoc является 1234h. Оно считывается из памяти со смещением 5002h в сегменте данных. Один из способов считывания данного значения состоит в загрузке в регистр bx, si, di или bp смещения MemLoc и использовании данного регистра для адресации к памяти. Инструкции
mov bx,OFFSET MemLoc mov ax,[bx]
загружают значение MemLoc в регистр ax. Значение MemLoc можно также загрузить непосредственно в ax с помощью инструкции
mov ax,MemLoc
58
или
mov ax,[MemLoc]
Здесь значение 1234h получается как прямой, а не как непосредственный операнд: инструкция mov использует встроенное в нее смещение 5002h и загружает в ax значение по смещению 5002h, которое в данном случае равно 1234h.
Часто встречающейся ошибкой является то, что часто забывают использовать операцию offset, например:
mov si,MemLoc,
где нужно использовать смещение MemLoc. На первый взгляд, данная строка не выглядит неправильной, и так как MemLoc это переменная размером в слово, то эта строка не приведет к ошибке ассемблирования. Однако при выполнении в si будут загружены содержащиеся в переменной MemLoc данные (1234h), а не ее смещение (5002h) и результаты будут непредсказуемы.
Надежного способа избежать этой проблемы нет, но можно принять за правило заключать все ссылки на память в квадратные скобки. Когда перед ссылками на адресные константы будет указываться префикс OFFSET, а ссылки на память заключаться в квадратные скобки, это устранит двусмысленность и неопределенность при использовании имен переменных памяти. При таком соглашении работа инструкций
mov si,offset MemLoc
и
mov si,[MemLoc]
становится совершенно понятной, в то время как инструкция mov si,MemLoc
будет настораживать.
1.Зубков С.В. Assembler для DOS, Windows и UNIX. / С.В. Зубков 11-е изд.,
стер. М.: ДМК Пресс; СПб.: Питер, 2010. 640 с.
2.Бурдаев О.В. Ассемблер в задачах защиты информации / О.В. Бурдаев, М.А. Иванов, И.И. Тетерин Под ред. И.Ю. Жукова. – 3-е изд., стер. – М.: КУДИЦ-
ОБРАЗ, 2008. – 544 с.
59
3. Абель Питер. Язык и программирование для IBM PC. / Питер Абель. Издво КОРОНА-Век, 2009.
60