Вопрос по 3 заданию из 5 лабы. “Внутри AddRightDigit косвенное обращение по адресу [локальной] переменной должно происходить при помощи регистра BP, так как переменная изначально выделена в сегменте стека.” Если у AddRightDigit 2 аргумента: цифра(сдвиг 6) и адрес числа(сдвиг 4), к которому мы должны приписать эту цифру, и в другой подпрограмме я кладу на стек сначала эту цифру, а потом локальную переменную -2(BP), когда я в AddRightDigit обращаюсь к 4(BP) это правильно?
Локальную переменную положить никуда нельзя, нужно положить её адрес. То есть число, равное BP - 2. Это можно сделать так, например:
MOV AX, BP
SUB AX, 2
PUSH AX
Можно чуть быстрее:
LEA AX, -2(BP)
PUSH AX
Эффект будет тот же. Про LEA можно погуглить.
Дальше внутри AddRightDigit
этот адрес нужно загрузить в BP
, предварительно сохранив предыдущее значение BP
на стеке, и обратиться по нему как обычно: (BP)
.
то есть если написать
PUSH -2(BP)
то на стек положится значение этой переменной?
Конечно.
обязательно BP? BX/SI/DI нельзя?
Ну, вы можете проверить, по крайней мере. Тут два соображения.
-
Если вы вспомните о том, что говорилось на прошлой лекции, то поймёте, что адрес
(BP) = (SS:BP)
, и он в общем случае не равен(BX) = (DS:BX)
, даже если положить вBP
иBX
одинаковые значения. -
Мы работаем на очень упрощённом симуляторе. Как он там учитывает сегментную часть, я точно не знаю: надо или экспериментировать (чего я не делал) или найти в тексте приложения про этот ассемблер в книге. Если вы разберётесь, что да как (например: симулятор вообще не учитывает сегмент или симулятор всегда делает сегментные части равными 0x0000, потому разницы нет) и напишите здесь, то будет здорово.
Но в реальном мире (не на симуляторе) всё же действует проблема 1, я думаю. Правда, в реальном мире можно явно указать сегментную часть, то есть писать код наподобие (SS:BX)
. Но в нашем опять-таки очень упрощённом ассемблере, насколько я понимаю, так нельзя: это связано или с его ограничениями или с ограничениями моделируемого им старого процессора Intel 8088 (тут тоже надо бы разобраться).
Я просто сначала написала вспомогательную подпрограмму AddRightDigit, она сама по себе работает, если ей любое число и цифру дать, а так получится, что она внутри будет связана с подпрограммой, которая переставляет цифры в обратом порядке, из-за вот этого всего.
Если я правильно поняла конечно. Так и написать?
Я не знаю, как вы её написали, но на мой взгляд никак изменить значения «снаружи» кроме передачи адреса (это то, что я предлагаю) нельзя. Ну, если не использовать глобальные переменные или не редактировать значения прямо на стеке или в регистрах (что является вариацией на тему глобальных переменных и плохо).
Хорошо. А можно в AddRightDigits AX и CX сохранить на стеке, чтобы их не испортить?
По cdecl эти регистры сохраняются вызывающей подпрограммой, а не вызываемой.
будет что-то вроде
PUSH BP
MOV BP, 4(BP)
...
POP BP
eсли в 4(BP) адрес переменной, да?
Да, именно так.
Cпасибо, вроде разобралась
737 стр. Таненбаума:
На самом деле, сегмент данных и стековый сегмент относятся к одной и той же области памяти, но данные хранятся на дне этого общего сегмента, а стек — на вершине.
оно?
Да, точно, спасибо. Это так называемая модель TINY, они используют её по умолчанию и не дают других возможностей. В реальности бывает по-разному.
Поэтому работает только с BP?
Нет, судя по тому, что написано, тут должно работать с любым регистром. А вообще, в других ассемблерах — необязательно.
Артем Михайлович, я забыл указать в своих файлах с кр номер варианта и фамилию=( Если это как-то поможет делу - Галайчук Виталий, второй вариант.
Хорошо, принято. Но оценка будет снижена. Я многократно обращал внимание на необходимость следовать требованиям оформления.
Опубликовано очередное ДЗ, слайды к лекции и материалы к ней. Поскольку тема достаточно сложная, я настоятельно рекомендую прочитать нужные разделы книги Таненбаума (указаны, как обычно, во вступлении к ДЗ).