· Начало · Статистика · WASM.RU · Noir.Ru ·

 WASM Phorum (Оффлайн - 24.11.2003) —› WASM.ASSEMBLER —› для главаря дZенствующих

Посл.отвђт Сообщенiе


Дата: Ноя 25, 2002 00:24:04

взято из введения
----------------------

#4. Те, кто внимательно ознакомились с циклами, они и на этом не остановятся! Посмотрев на адреса 110...119, они вообще возьмут и возомнят себя воистину крутыми парнями! Знаете, что они напи-шут? А вот что (предвидим!):

:0100 XOR AL,AL
:0102 MOV BH,10
:0104 MOV CH,05
:0106 MOV CL,10
:0108 MOV DH,10
:010A MOV DL,3E
:010C MOV AH,06
:010E INT 10
:0110 MOV CX,0004
:0113 CALL 011A
:0116 LOOP 0113
:0118 INT 20
:011A ADD BH,10
:011D ADD CH,01
:0120 ADD CL,01
:0123 SUB DH,01
:0126 SUB DL,01
:0129 INT 10
:012B RET

То бишь еще и CALL в цикл при помощи MOV CX,4 и LOOP'а "закрутят". И что? А попробуйте!

Что, не "пашет"? А что надо делать, если "не пашет, а должно бы"? Правильно! Смотреть из-под отладчика!

Смотрим? Если посмотрите, то сразу же и "загвоздку" увидите - CX, использованный в качестве "счетчика" циклов, "перебивает" тот же CX, но используемый как "координаты верхнего левого угла окна". И что с этим делать прикажете?

Вот, вы и столкнулись с одной из самых больших проблем. В процессорах фирмы Intel есть только 4 регистра общего назначения (и то в большинстве случаев - специализированных). Помните, мы вам говорили об этом?

А теперь попробуйте выкрутиться из этой нехорошей ситуации с использованием стека :). Кстати, весьма "мозгопрочищающая" задачка :).

вот я и пробовал. нашел два варианта и не один из них не работает вот и встал вопрос, а возможно ли разоешить проблему используя стек и не используя ни bp ни sp ???

мои варианты (не работающие) :)


--------
1 xor al,al
2 mov ah,06
3 mov bh,10
4 mov cx,0510
5 mov dx,103e
6 int 10
7 push cx ;сх в стек
8 mov cx,0004
9 call 12
10 loop 9
11 int 20
12 add bh 10,
13 pop cx ;здесь адрес возврата
14 pop cx ;а здесь тот сх что нужен, к кот. добавлять будем
15 add cx,0101
16 sub dx,0101
17 int 10
18 push cx ; сохранить для следующего раза
19 ret

и вот ret возвращает меня не туда. сх у меня перед ret 0611 (0510+0101 = 0611) и ret меня возвращает на адресс 0611. пробовал перед ret вставить mov cx,10 шоб он меня возвращал к loop, но не работает.

2-ой вариант
--------------------
1 xor al,al
2 mov ah,06
3 mov cx,4 ; 4 раза повторять саll
4 push cx
5 jmp 9
6 call 14
7 pop cx ; здесь востанавливается 4
8 loop 6
9 mov bh,10
10 mov cx,0510
11 mov dx,103e
12 int 10
13 jmp 6
14 add bh,10
15 add cx,0101
16 sub dx,0101
17 int 10
18 ret

ве равно не работает. первый раз все как надо вычитает из 0510 0101 вызывает 10 прерывание все ок. востанавливает 4. лууп уменьшает на еденицу, видит что не равно 0 и вызывает сall и вот тут то сх остается 0003 а надо 0611...

так есть ли решение, или это такая подеб-ка (ведь смайлик вроде в статейке)

зы. у меня пальцы болят от T-Enter T-Enter T-Enter ....


Дата: Ноя 26, 2002 10:48:46

Правильной дорогой идешь, товарищ! С loop'ом эта задачка действительно не имеет решения. Но ведь loop - не единственная команда, с помощью которой можно организовать цикл ;)

Просьба считать эту задачку разновидностью "хлопка одной ладонью", а не подеб-кой ;).


Дата: Дек 10, 2002 01:01:35

Any register (a,b,c,d,si,di) can be a loop counter:

MOV ANY_REG, NUMBER_OF_TIMES

NEXT_ITERATION:
; --- loop body, damage the CX all you want...
DEC ANY_REG
JNZ NEXT_ITERATION


Дата: Дек 14, 2002 12:37:26

Чтобы отдельной темы не заводить, сюда же напишу...

В статье "Hello, World!" и три халявы..." допущена ошибка в исходниках. Не знаю, как у остальных, но у меня, когда я запускал полученную программу она "выполняла недопустимую операцию".
После внимательного просмотра исходных данных обнаружил, что WriteConsoleA требует указатель для внесения числа реально выведенных символов, а мы ей подсовываем 0, который вроде как указателем не является (или это указатель на базу сегмента?). В любом случае, программа заработала без ошибок, только когда я ввел в сегменте данных поле
nWrtnSymbols dd 0
а процедуре WrtieConsoleA в соответствующем месте передал через offset указатель на это поле.
И возник у меня вопрос: чем отличается offset от addr (вроде бы где-то написано, что addr работает всегда, а у offset - ограничения есть, но все же...) и много ли я потеряю, если буду везде использовать addr?


Дата: Фев 5, 2003 04:26:08 · Поправил: SolidCode

По поводу offset и addr.
Addr может использоваться только в рамках вызова invoke, а offset это родной оператор ассемблера.

Сначала определимся.
Оффсет в вызове invoke это (напр.)
push int32, где числом (готовым значением) передаётся адрес переменной. То есть это одна инструкция.
А addr это
lea eax,[int32]
push eax,
то есть адрес считается на месте и передаётся через регистр eax.

При использовании в процедурах для передачи параметров, я предпочитаю оффсет для глобальных переменных. А для локальных идёт только аддр, т.е. считаем адрес на месте не отходя от кассы.
offset короче по длине, и выполняется одной инструкцией. А addr реализуется двумя, причём, хотя парно выполняются lea и push в любых конвейерах свободно, в данном случае они будут выполняться не одновременно, потому что значение, помещаемое в стек (eax), зависит от предыдущей операции (lea eax,??). Единственный случай, когда стоит использовать addr, это для локальных переменных.
Ещё одна проблема с addr в том, что используется регистр еах. Поэтому, если вы хотите передать следующей процедуре результат от предыдущей, не сохраняя его в переменную, то приходится обходить addr каким-либо образом:
LOCAL rec:RECT
invoke GetDesktopWindow
invoke GetClientRect,eax,addr rec
Этот вариант не пойдёт, потому что еах (хэндл десктопа) потерялся при выполнении addr. Можно сделать так:
invoke GetDesktopWindow
lea edx,rec
invoke GetClientRect,eax,edx
В данном случае мы разбили наш addr самостоятельно и используем другой регистр для вычисления адреса локальной переменной.

Более подробно об их различиях посмотри во втором уроке tutorial'а от Iczelion. Советую под дебаггером посмотреть их реализацию в кодах и решить для себя, где который способ использовать.


Дата: Фев 5, 2003 16:11:06

Интересно...

Знаешь, kompot, первый вариант работает, но для этого надо чуть-чуть подумать:
13 pop cx ;здесь адрес возврата
14 pop cx ;а здесь тот сх что нужен, к кот. добавлять будем

- это конечно хорошо, но адрес возврата теряется безвозвратно (извините за тавтологию :)
18 push cx ; сохранить для следующего раза
19 ret

А здесь он(адрес) и не возвращается на свое законное место (т.е. в стек) перед ret`ом

не лучше-ли сделать так(?):

13 pop si
...
18.5 push si


PS: ... или в задаче можно использовать только 4 вышеперечисленных регистра?


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.087