Мысли
о
Паскале
г
Владислав ДЕМЬЯНИШИН
www.i.com.ua/~amonit
Продолжение, начало см. в М К, N s 46, 51 ~ 5 2, 4, 6 -7 , 10, 1 2 -1 3 , 1 6 -1 8 , 22, 24, 29, 34, 41, 46, 4, 6, 17, 21, 23, 28,
30, 32, 39, 42, 45, 47, 52, 2, 7, 18 -1 9 , 23, 37, 39, 45, 48, 50, 52, 5 (165, 1 7 0 -1 7 1 , 175, 1 7 7 -1 7 8 , 181, 183-184, 18 7 -1 8 9 ,
193, 195, 200, 205, 212, 217, 227, 229, 240, 244, 246, 251, 253, 255, 262, 265, 268, 270, 275, 277, 282, 293-294, 298,
312, 314, 320, 323, 325, 327, 332)
Специальные asrn-идентификаторы
П
ри прогроммировании на ассемблере помимо доступа к пере-
менным может понадобиться доступ к сегменту данных и кодо
программы, например, в процедуре обработчика прерывания.
Для этих целей предусмотрены два идентификатора —
©Data
и
©code,
соответственно для сегмента данных и кода. Эти идентифи-
каторы следует использовать совместно с оператором
SEG
asm
m o v a x , SEG © Data
m o v a x , SEG ©Code
end;
Такие комбинации компилируются в инструкцию загрузки кон-
стантного значения соответствующего номера сегмента в регистр
а х ,
что позволяет, например, восстановить значение сегментного
регистра
DS,
если его зночение было утеряно. Необходимо знать,
что стондортная функция
d s e g
возврощает не номер сегмента дан-
ных, о текущее значение сегментного регистра
d s .
Во встроенном ассемблере имеется еще один идентификатор,
© R e su lt,
который может применяться только в функциях и служит
для передачи результата во временную переменную для хранения
результата, расположенную в стеке. Следующий пример иллюстри-
рует, как можно изменять и получать зночение результата функции
внутри asm-оператора:
f u n c t io n C le a rW o rd : w o rd ;
b e g in
asm
x o r A X , AX {обнуляем р е ги с т р AX)
m ov © R e s u lt, AX
mov AX , © R e su lt
end;
end;
Немного по-другому обстоит дето с возвращением результата
ти-
па S trin g .
Дело
в
точ что применительно
г.
типу
S t r in g
идентифика-
тор
© R esult
подразумевает адрес помяти не самой переменной,
а
адрес указателя
на
переменную, поэтому следует извлечь адрес
с е г -
мент см ещ ение
и загрузить его в регистровую пару, удобную для дос-
тупа к области строки, например, в
E S :D i.
Затем индексировать реги-
стром
d i
обращение
к
помяти, где хранится результат строчного типа,
f u n c t io n G e t S t r : s t r in g ;
b e g in
asm
MOV D I , w o rd p t r © R e su lt
MOV A X , w o rd p t r © R esult+ 2
M O VES, AX
M O VAL, 2 {длина ст р о к и б у д е т 2 сим вола)
M O VES: [D I] , A L
IN C D I { п е р е х о д н и к следую щ ему б а й ту стр о к и )
M O VAL, 'А ' {пер вы йсим вол б уд е т 'А '}
M O VES: [ D I ] , A L
IN C D I {переходим к следующ ему б а й ту стр о к и )
M O VAL,
'В '
{ в то р о й си м в о л б у д е т 'В '}
M O VES: [D I] , A L
end;
end;
Первые три строки из данного примера можно заменить одной,
выполняющей ту же операцию загрузки укозотеля в регистровую
пару
E S :D I - се гм ен т:см ещ ен и е ,
причем
в ES
сегмент, а
в DI,
со-
ответственно, смещение. При этом регистр
а х
не задействовон.
Тогдо код функции
G e t S t r
станет короче:
f u n c t io n G e t S t r ; s t r in g ;
b e g in
asm
LE S D I , © R e su lt
M O VAL, 2
M O VES: [D I] , A L
IN C D I
M O VAL, 'A '
M O VES: [D I] , A L
IN C D I
M O V A L, 'B '
M O VES: [D I] , A L
end;
end;
Бывает, что логика кодо функции строится на поэтапном форми-
ровании результата, причем каждый последующий этап базируется
на значении результата, полученном при выполнении предыдущего
этапа. Но записывать в переменную результат можно было только
указывая идентификатор функции в левой части присваивания, ток
как указание оного в правой части оператора присваивания рас-
ценивалось бы компилятором как рекурсивный вызов. Чтобы как-то
выйти из данной ситуации приходилось объявлять локальную пере-
менную такого же типа, что и тип результата функции. При этом уве-
личивался расход стека, что при использовании рекурсии заметно
снижало количество возможных рекурсивных вызовов. В этом щекот-
ливом деле неожиданно на помощь пришла гибкость встроенного
оссемблера. Спрашивается, зачем выделять лишнюю помять под вре-
менную переменную для хранения результата, когдо перед вызовом
функции память под результат уже была выделена. Особенно это ко-
сается функций, возвращающих результат строчного типа. Так, но-
пример, достаточно объявить переменную типа указатель на стро-
ку, в донном случае
M y R e su lt,
затем при помощи короткого ассемб-
лерного оператора одрес памяти в стеке, зарезервированной под
результат, загрузить в объявленный указатель
M y R e s u lt
и в дальней-
шем при помощи разыменования указателя легко и свободно вы-
полнять с результатом все действия, кокие только заблогороссудит-
ся. При этом значение результата функции всегда будет определе-
но, несмотря на то, что в теле функции нет ни единого оператора
присваивания с идентификатором функции в левой части,
f u n c t io n G e tS tr : s t r in g ;
v a r M y R e s u lt : * s t r in g
b e g in
asm
mov A X , w o rd p t r © R e su lt
mov w o rd p t r M y R e s u lt, AX
mov A X , w o rd p t r © Result+ 2
mov w o rd p t r M y R e su lt+ 2 , AX
end;
M y R e su lt* := '1 0 ';
M y R e su lt* := M y R e su lt* + '4 0 ';
end;
Хотя это и не эффективно, но аналогичным оброзом можно по-
ступить и с функциями, возвращающими результат любого другого
типа. Такой метод доступа к результату, скорее всего, может лишь
сделать код функции нагляднее, поскольку с точки зрения экономии
стека для таких типов, кок целые и вещественные, такой метод убы-
точен. При этом получить смещение переменной в памяти можно ин-
струкцией
LE A А Х , © R esu lt,
а сегмент — из сегментного регистра
SS
f u n c t io n G etW ord : w o rd ;
v a r M y R e s u lt : *w ord;
b e g in
asm
№ 8/335 2 ] февраля-28 февраля 2005
предыдущая страница 38 Мой Компьютер 2005 08 читать онлайн следующая страница 40 Мой Компьютер 2005 08 читать онлайн Домой Выключить/включить текст