Здраствуйте! 1. на 32 битном процессоре, в стек можно положить только 32 битное знаечение? строку например из 10 байт никак не положить? 2. и для чего нужен регистр ebp? ответьте пожалуйста на эти вопросы
Это ещё почему. Стек - это обыкновенная память. Код (Text): mov eax, esp mov byte ptr [eax], 'a' EBP - регистр - указатель базы, для адресации локальных переменных, но конечно не обязательно.
команда PUSH по дефолту кладет 32 бита (это зависит от разрядности кода). С префиксом 66 может положить и слово. Байт она не кладет никогда. Другой вопрос - положить чтото в стек напрямую через ESP. sub esp, 1 ; заталкиваем mov byte [esp], 4 add esp, 1 ; выталкиваем
Присоединяюсь к вопросу о ebp. Никогда не понимал, зачем он нужен. Слова "указатель базы кадра стека" ни о чем не говорят. Точнее говорят, но как указатель может использоваться тот же eax, например. Чем ebp лучше чем еах? В большинстве подпрограмм, например, ebp используется в качестве копии esp: Код (Text): push ebp mov ebp, esp .... mov ecx, [ebp+6]; (доступ к аргументу) .... mov esp, ebp pop ebp Чем следующий код хуже? Код (Text): push eax mov eax, esp .... mov ecx, [eax+6]; (доступ к аргументу) .... mov esp, eax pop eax
l_inc Ничем. Просто у регистров есть свои имена =) ecx - например счетчик. Просто как правило стараются использовать одни регистры для одинаковых целей.
1) когда внутри функции ты сделаешь несколько push, у тебя esp изменится. Как тогда аргументы достать? В ebp запоминают esp при входе в функцию. Чтобы из любой точки можно было достать аргументы: Код (Text): push ebp ; старый ebp mov ebp, esp ; сохраняем esp в ebp push 1 push 2 push 3 ; все равно мы теперь сможем достать аргументы через ebp, а через esp уже не сможем. 2) Чем хуже eax? Ничем. Просто в процессоре i8086 косвенная адресация была доступна только через определенные регистры. Это потом начиная с 386 можно адресовать через любой регистр, в том числе и eax. А в 8086 адресация была фиксированная. Самым удобным был регистр BP, который изначально был зарезервирован для этой цели - доступ к стеку. BP = Base Pointer. Начиная с 386 все 16битные регистры расширились до 32битных и получили префикс E. Регистр BP стал EBP - Extended Base Pointer. Назначение осталось тем же. Просто договорились использовать именно его для этих целей. Хотя это не обязательно. В нем можно хранить что угодно
l_inc Да ничем, просто eax, как правило используется для других операций, а ebp - только как указатель на стек. Ведь не сможешь же использовать div без eax. А в твоём коде его надо будет куда-то сохранять. И вообще читайте про назначение регистров. Какие в каких операция целесообразнее использовать.
Другая причина, как я сказал, это то, что в 8086 нельзя адресовать через ax. Система косвенной адресации была очень жесткой Насколько я помню, в качестве базовых регистров допускались только BP, BX, SI, DI. Нашел схему адресации в 8086/80286: [ BX/BP + SI/DI + IMM16 ]
Добавлю еще, что при использовании ebp сегментным регистром по-умолчанию будет ss, т.е. сегмент стека. Интересно, а сама идея стековых кадров пришла еще во времена 16 бит? Я так понимаю, основная причина их появления -- невозможность адресоваться по sp...
а когда еще то =) Стековые кадры под досом тоже были Основная причина скорее всего другая. Возможность простого доступа к аргументам текущей и вышестоящих функций независимо от SP.
Booster Какие регистры целесообразно использовать, ИМХО, зависит только от логики работы программы. И если мне не нужно использовать операции с фиксированным аргументом (или результатом работы) в eax (в принципе, я его только для примера привел; не будем использовать цепочечные команды, будем хранить указатель кадра в esi), то почему бы его не использовать для этих целей; конечно приходилось бы больше жаться, но в программках на асме жаться всегда приходится, а лишний регистр в процессоре, ИМХО, - роскошь. To all А вообще, спасибо. А то я думал, что только мне bp/ebp лишним кажется. Тем более, как оказывается, к стеку он (в плане архитектуры ЦП) никакого отношения, кроме названия, не имеет (Mika0x65, спасибо, Ваш аргумент по поводу сегментного регистра по умолчанию учел).
На самом деле в винде сегментный регистр значения не имеет, у CS, DS, ES, SS стоит одинаковая база и равная 0. Таким образом виртуальный адрес во всех сегментах совпадает с линейным. Один FS стоит особняком. Но в том же досе это не так =) Так что замечание, безусловно, полезное. Ну не скажи.. Все же, ИМХО, стоит придерживаться общепринятых принципов. Конечно, никто не запрещает, например, возвращать из функции значение в EBP, однако было бы логичнее это делать через EAX. ECX часто используется для счетчика. А EBP часто используется для хранения кадра стека.. В маленьких функциях, конечно, можно обойтись и без кадра стека. Например, функция сложения своего аргумента и десяти: Код (Text): func: mov eax, [esp+4] add eax, 10 ret 4
green Дык это ж и есть те самые пролог/эпилог, которые я приводил, пытаясь объяснить, почему мне ebp лишним кажется. Если бы при работе с ebp в ЦП предлагалась какая-то особая поддержка для работы со стеком, тогда можно было бы сказать, что он архитектурно выделяется. А так - просто лишняя ячейка памяти с особым названием. С таким же успехом можно было бы добавить регистр mcx (MyCool register) и сказать, что общепринятым считается хранить в нем только самые крутые значения в программе. Так что замечание не принято. P.S. RuAsm Извиняюсь, что перехватил тему. Надеюсь, что комментарии форумчан к моему вопросу были полезными при ответе на ваш вопрос о ebp.
ESP - тоже ничем абсолютно не выделяется, если судить по твоим критериям. Подумаешь, там принято хранить адрес стека. Я могу там и числа перемножать. Кто запретит?
Great Не а. Не согласен. Esp вполне очевидно используется при работе с командами pop/push. Его значение неявно изменяется, как часть алгоритма работы операций, являющихся частью архитектуры МП. А ebp - действительно просто ячейка памяти.
А значение ebp неявно изменяется при enter/leave. А значение ECX меняется неявно при loop, значение esi(edi) при цепочечных командах, .... Список продолжить сколько команд неявно меняют регистры? Чем ESP по-твоему такой "особенный", а EBP такой "обычный" ? имхо, они одинаковы по своей "обычности"
Ой. Забыл, что enter/leave - не директивы транслятора и не макросы (хотя и макросы тоже). Теперь почти согласен. "Почти": но разве enter/leave не были введены, начиная с 286-го? А назначение за bp (как и сам bp) закрепилось, подозреваю, раньше. Ну... я спрашивал только о ebp. Все остальные регистры мне не казались лишними.
в 8086(286) использование sp и bp по умолчанию подразумевало сегмент ss для остальных регистров это был ds, и хотя можно было и явно указать ss:[bx] но это было на байт длиннее. Можно конечно прямо использовать esp не заморачиваясь на ebp, но тогда придется самому отслеживать уменьшение/увеличение esp после всех push/pop в маленькой процедуре это еще приемлемо, mov [esp+8],eax (89442408 - 4 байта) mov [ebp+8],eax (894508 - 3 байта)
Назначение за bp закрепилось раньше, потому что на 8086 нельзя было адресоваться через sp - это раз. А как тогда обращаться к переменным в стеке если адресация через остальные регистры предусматривает в качестве сегмента по умолчанию ds. Плюс сегментация тогда активно использовалась (впрочем и сейчас тоже, только не в Win) - так что ds!=ss в очень многих случаях. А писать каждую команду с префиксом - это лишние байты и лишние такты при декодировании. Кстати, раз уж пошло обсуждение архитектуры. Никто не в курсе что значит r в x64? Ну то есть eax - extended ax, а rax - это что? Я думаю не от болды ведь