могу понять, нужны ответы на вопросы: "Почему это нужно делать?" "Что, если сделать по-другому?", " Что, если этого не делать? ", а вот " Как это сделать?" - показано.
Ну это странный вопрос... Смотри: ; Сохранить оригинальный ESP в EBP ; В ESP установить указатель на самописный стэк push eax ; Теперь в нашем стэке [stack_start] будет значение EAX ; Восстанавливаем оригинальный стэк из EBP в ESP
Если не делать mov ebp, esp В данном случае - тогда как нам восстанавливать настоящий изначальный стэк? Нужен какой-то регистр, где будем хранить оригинальный указатель. Можно сделать и так: mov edi, esp mov esp, mystack push eax mov esp, edi push eax @lan219 Понял?
Просто повытягивать от туда pop'oм в регистры и обнулить их
push/pop не будет работать, мы изменили адрес стэка, мы изменили ESP А push/pop работают с ESP, какое-бы там значение ни было
Ясненько... Значит, ни одна книга, на русском языке, по ассемблеру мне не помогает..😢. Есть английские только хорошие книги, в смысле, не просто описание инструкций и примеры их работы, а примеры программ, какие-нибудь практические задания и т.д. Ведь какой ЯП учат просто по описаниям функций? Знания не систематизированны, не показано как и зачем этим пользоваться и т.д
И желательно для новичков..
Ну что? Есть ли какие-нибудь книги? Или свою продолжать читать?
можно просто запомнить сколько стека мы выделили, так делают компиляторы, когда оптимизируют
Тебе же уже советовали - ставь задачу перед собой, и формулируй вопросы в Google. На основе выданных результатов ты получаешь ещё одну формулировку, и так пока не дойдёшь до ответа, предварительно ещё вычитав кучу информации в интернете. Это лучше книг, в наше время
Предлагаешь дать новичку пример с оптимизированным кодом?
Так я не знаю, часто, какую задачу ставить себе-то. Я же чертов новичок, нихрена не шарящий в ассемблере..
не, ему это рано пока
Тут проблема не в том, что новичок. Просто ты убедил себя, что не можешь начать писать код самостоятельно. Главное - написать самому первую строку кода, а дальше пойдёт фантазия, автоматически начнёшь искать информацию, и так далее...
Уже написал hello world (или что-то типа этого), и создал файл, и запхнул в него данные - через пот и кровь все это
Вот эту для школотронов попробуй. Если не поможет, значит уже целая библиотека имени Крупской не поможет.
Вот есть к примеру у тебя printf, и ты для него пушиш аргументв стек, свой текст например, так вот когда ты его пушишь esp автоматически сдвигается и если у тебя была какая то переменная к которой ты обращался по адресу esp то теперь она уехала в esp+4, потому что esp автоматически всегда на вершине стека, так вот если ты перед printf скопируешь esp в ebp то ты всегда сможешь обратиться к ebp и относительно него к локальным переменным той прошлой процедуры, той которая была до printf, это типа такой снепшот, заморозка состояния esp, кроме того ты всегда сможешь почистить стек от использованых переменных функций которые уже отработали вернувшись к тому состоянию, скопировав адрес ebp обратно в esp, это надо делать чтобы стек не пух иначе в итоге может крашнуться система, вообще для этого есть комманды call/ret enter/leave чтобы не делать этого вручную. Есть еще несколько стандартов неписания функций, они по разному работают со стеком, stdcall _cdecl fastcal, какие то чистят за собой стек какие то нет, т.е. ты должен будешь делать это сам тогда
чтоб относительно обновленного ebp, который получается из esp после загесения в стек аргументов и адреса возврата, можно так же было обращаться еще и килокальным переменным. [ebp+...] это обращение к параметрам [ebp-...] это обращение к локальным переменныи
Перед тем как вызвать процедуру ты заносишь в стек параметры, когда вызываешь процедуру, call заносит в стек еще и адрес возврата. При каждом занесении чего то в стек, указатель вершины уменьшается. Поэтому, когда ты зашел в процедуру и спас ebx (тож в стеке),, а потом присвоил ему адрес вершины на этот момент, получается что все параметры находятся выше bp, а все, что еще наколотили в стек в процедуре будет ниже bp. Просто так через pop ты параметры не достанешь, так как там еще адрес возврата хранится. Как то так.
Проще: call - заносит адрес возврата на данный указатель стэка ([esp]), а push: sub esp, 4 ; или 8, и rsp mov [esp], operand Таким образом, стэк будет выглядеть так: ESP = 0x400008 push eax ; ESP = 0x400004 (значение EAX находится на 0x400008) call func ; ESP = 0x400004 То есть, push положил значение EAX в 0x400008, и уменьшил указатель на 4, а call просто положил адрес возврата на данный указатель, он не уменьшал. Таким образом, чтобы взять аргумент, нужно сделать [ESP+4], потому что на [ESP] будет адрес возврата. А что делает pop: mov operand, [esp] add esp, 4 ; Или 8, и rsp То есть, он возьмёт адрес из данного указателя на стэк, где лежит адрес возврата, а после чего увеличит ESP на 4, таким образом, ESP уже будет на +4, где нет никакого адреса возврата, вместо него там лежит наш параметр. По-сути, взять параметр через pop - можно. Нужно сделать так: add esp, 4 pop eax sub esp, 8 ret То есть: [ESP] -> Адрес возврата [ESP+4] -> Параметр После выполнения pop -> ESP будет стоять уже на +8, потому что он делает ещё один add esp, 4, поэтому его нужно вернуть на наш адрес возврата. Для x64 будет: add esp, 8 pop eax sub esp, 16 ret Но делать так не нужно, смысла от этого - ноль
Офигеть... Спасибо Вам всем.
Обсуждают сегодня