Ассемблером я только начал заниматься, поэтому помогите мне с такой штукой: LOCAL wc:WNDCLASSEX LOCAL msg:MSG LOCAL hwnd:HWND mov wc.cbSize,SIZEOF WNDCLASSEX mov wc.style, CS_HREDRAW or CS_VREDRAW mov wc.lpfnWndProc, OFFSET WndProc mov wc.cbClsExtra,NULL mov wc.cbWndExtra,NULL push hInstance pop wc.hInstance Вот такой код, вроде не сложно, но объясните мне такие, вещи: 1. Вот LOCAL что значит. В справочном материале написано, что это резервируется память в стеке. А что будет если я превышу тот размер, который зарезервировал? 2. Вот есть строчки push ... и pop ... Зачем они сделаны, разве нельзя было сделать mov wc.hInstance,hInstance? Вроде пока все вопросы
LOCAL - макрос. Он определяет, что wc, msg и hwnd будут транслироваться препроцессором в конструкцию вида [ebp - XXX], где XXX - определённое число. Если регистр ebp указывает на начало стекового фрейма, то конструкции подобного рода будут указывать на локальные переменные, которые, как известно, хранятся в стеке. Понять принцип стекового фрейма проще всего взглянув на рисунок. "Рисунок" стека можно увидеть в отладчике. OllyDbg для этого идеально подходит. Если использовать слишком много места на стеке, то стек может переполниться. Скажем, если Вы создаёте в стеке локальный массив размером в 1Мб, то возможность переполнения следует учитывать. В таком случае процессор сгенерирует исключение и его можно обработать и увеличить размер стека, но по началу лучше просто избегать подобных ситуаций и не выделять на стеке больше 1-2Кб. Микроинструкция mov не поддерживает форму, в которой оба операнда указывают на память. Приходится копировать через регистр (eax, edx, ecx, ...) или через стек (push + pop).
Народ кто знает что надо написать на асме, чтобы вызвать вот такую байду "public: void __thiscall TStringTag::SetValue(char const *)" из DLL ?
Это я опять со стеком. Насколько я знаю в стек значения ложаться как по принципу первым пришел - последним ушел. А здесь что же получается я могу одновременно обращаться и к wc и к msg и hwnd? Как это реализуется, компилятором?
nmn Именно так работают инструкции push/pop. Но стек - это такая же область памяти как и секция данных или секция кода или кусок динамической памяти из хипа. Поэтому к переменной на стеке можно обращаться напрямую, если известен её адрес. Макрос LOCAL, стековый фрейм, пролог и эпилог функции, подсчёт эффективного адреса через регистр ebp (конструкции типа [ebp + XXX]) служат только для того, чтобы получить этот самый адрес. К примеру, если esp указывает на верхушку стека, то следующий код: Код (Text): mov eax,[esp + 4] помещает в eax то, что лежит в стеке во второй 32-битной ячейке сверху. Т.к. регистр esp имеет "склонность" изменяться с каждым push/pop и другими стековыми операциями, то имеет смысл задействовать ещё один регистр чтобы запомнить начальное значение esp: Код (Text): mov ebp,esp Теперь не важно сколько push'ов и pop'ов будет следовать дальше - ebp будет указывать на оригинальную верхушку стека. Поэтому к локальным переменным и к параметрам функций обычно обращаются именно через ebp, а не на прямую через esp. К тому же адресация через esp занимает на 1 байт больше чем через любой другой регистр. Таким образом, "теряя" один регистр (обычно ebp) мы упрощаем код и выигрываем в размере. Код (Text): mov eax,[ebp + 4] Занимает 3 байта. Код (Text): mov eax,[esp + 4] Занимает 4 байта. Фиксация начального значения верхушки стека как бы создаёт локальную версию стека для функции. Это и называют стековым фреймом или кадром (stack frame).