Stack pointer что это

Указатель стека AVR

Стек в основном используется для хранения временных данных, локальных переменных и обратных адресов после прерываний и вызовов подпрограмм. Регистр Указателя Стека (Stack Pointer Register) всегда указывает на верхнюю часть стека.

Обратите внимание, что Стек выполнен как растущий из более высоких расположений памяти в более низкие. То есть визуально Стек как бы перевёрнут (см. рис.). Это означает, что команда PUSH уменьшает указатель стека.

Stack pointer что это. stack avr. Stack pointer что это фото. Stack pointer что это-stack avr. картинка Stack pointer что это. картинка stack avr

Указатель Cтека (Stack Pointer) указывает на область данных SRAM Stack (статическая память, выделенная для стека), в которой расположены стеки подпрограмм и прерываний.

Указатель стека должен быть установлен выше 0x60.

Указатель стека уменьшается на единицу, когда данные помещаются в стек с помощью инструкции PUSH, и на два, когда возвращаемый адрес помещается в стек с помощью команды PUSH подпрограммой вызова или прерывания.

Указатель стека увеличивается на единицу, когда данные извлекаются из стека с помощью инструкции POP, и увеличивается на два, когда данные извлекаются из стека при возвращении из подпрограммы с помощью инструкции RET, или при возвращении из прерывания с помощью инструкции RETI.

Указатель стека AVR выполнен в виде двух 8-разрядных регистров в пространстве ввода-вывода. Это регистры SPL (Stack Pointer Low) и SPH (Stack Pointer High).

На рисунке показана структура регистра SPL, который расположен по адресу 0х3D. Все биты регистра доступны как для чтения, так и для записи. Начальные значения битов (Initial Value) также показаны на рисунке.

В регистры SPL и SPH необходимо загружать адрес вершины стека (адрес верхней границы ОЗУ).

Адрес вершины стека хранится в константе RAMEND, которая определена в подключаемом файле для данной модели микроконтроллера. Например, для микроконтроллера ATtiny13A в начале файла исходного кода программы надо подключить файл tn13def.inc.

Этот код надо разместить до вызова каких-либо подпрограмм.

Источник

Stack Pointer (SP)

Stack pointer что это. dark fb.4725bc4eebdb65ca23e89e212ea8a0ea. Stack pointer что это фото. Stack pointer что это-dark fb.4725bc4eebdb65ca23e89e212ea8a0ea. картинка Stack pointer что это. картинка dark fb.4725bc4eebdb65ca23e89e212ea8a0ea Stack pointer что это. dark vk.71a586ff1b2903f7f61b0a284beb079f. Stack pointer что это фото. Stack pointer что это-dark vk.71a586ff1b2903f7f61b0a284beb079f. картинка Stack pointer что это. картинка dark vk.71a586ff1b2903f7f61b0a284beb079f Stack pointer что это. dark twitter.51e15b08a51bdf794f88684782916cc0. Stack pointer что это фото. Stack pointer что это-dark twitter.51e15b08a51bdf794f88684782916cc0. картинка Stack pointer что это. картинка dark twitter.51e15b08a51bdf794f88684782916cc0 Stack pointer что это. dark odnoklas.810a90026299a2be30475bf15c20af5b. Stack pointer что это фото. Stack pointer что это-dark odnoklas.810a90026299a2be30475bf15c20af5b. картинка Stack pointer что это. картинка dark odnoklas.810a90026299a2be30475bf15c20af5b

Stack pointer что это. caret left.c509a6ae019403bf80f96bff00cd87cd. Stack pointer что это фото. Stack pointer что это-caret left.c509a6ae019403bf80f96bff00cd87cd. картинка Stack pointer что это. картинка caret left.c509a6ae019403bf80f96bff00cd87cd

Stack pointer что это. caret right.6696d877b5de329b9afe170140b9f935. Stack pointer что это фото. Stack pointer что это-caret right.6696d877b5de329b9afe170140b9f935. картинка Stack pointer что это. картинка caret right.6696d877b5de329b9afe170140b9f935

Указатель стека указывает на последнюю свободную ячейку стека. Область стека в ОЗУ должна быть задана до того, как произойдет любой вызов подпрограммы или будут разрешены прерывания. Указатель стека уменьшается на 1 при записи данных в стек командой PUSH и уменьшается на 2 при вызове подпрограммы командой CALL или обработке прерывания. Указатель стека увеличивается на 1 при выборе данных из стека командой POP и увеличивается на 2 при выполнении команд возврата из подпрограммы или обработчика прерывания (RET или RETI).

Сброс и обработка прерываний.

В AT90S8535 предусмотрено 10 источников прерываний. Эти прерывания и сброс имеют различные векторы в области памяти программ (FLASH). Каждому из прерываний присвоен отдельный бит в определенных регистрах управления. Если бит установлен в «1», и бит I регистра состояния SREG разрешает общее обслуживание прерываний, то данное прерывание будет разрешено. Например, для того, чтобы было разрешено прерывание INT0, необходимо, чтобы был выставлен бит INT0 регистра GIMSK.

Источник

Download Stack Painter 0.11 APK

Stack Painter

ID: com.climberman.stackpainter

Author:

Version:

Update on:

Other variants APKs:

Effects on battery life:

Category

Get it on:

Stack pointer что это. google play. Stack pointer что это фото. Stack pointer что это-google play. картинка Stack pointer что это. картинка google play

Requirements:

Stack Painter 0.11 APK for Android 4.4+

Version0.11 for Android 4.4+
Update on2021-02-20
File size19.257.288 bytes
Permissions view permissions
What’s newFixed bug.

Versions history:

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Cash Alarm: Games & Rewards

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Cookie Jelly Match

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Kitty Bubble : Bubble pop puzzle

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Expense IQ Money Manager

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Mi Bandage for Mi Band and Amazfit

Varies with device

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Write Name On Locket

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Varies with device

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Varies with device

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Pure Tuber: Block Ads on Video

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Earn Cash and Money Rewards Playing Games & Music

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Stack pointer что это. empty. Stack pointer что это фото. Stack pointer что это-empty. картинка Stack pointer что это. картинка empty

Banco do Brasil | Conta, cartão, pix e mais!

Share with friends

Recent updated Apps(172)

Hit android Apps(2623)

Recent reviews Apps(9419)

Источник

Что такое базовый указатель и указатель стека? На что они указывают?

используя исходя из Википедии, в которой DrawSquare () вызывает DrawLine (),

Stack pointer что это. 3d546bd971100314a8f19bed4f3f6170. Stack pointer что это фото. Stack pointer что это-3d546bd971100314a8f19bed4f3f6170. картинка Stack pointer что это. картинка 3d546bd971100314a8f19bed4f3f6170

(обратите внимание, что эта диаграмма имеет высокие адреса внизу и низкие адреса вверху.)

может ли кто-нибудь объяснить мне, что ebp и esp в этом контексте?

из того, что я вижу, я бы сказал, что указатель стека всегда указывает на верхнюю часть стека, а базовый указатель на начало текущей функции? Или что?

edit: я имею в виду это в контексте программ windows

edit2: а как же eip работы тоже?

edit3: у меня есть следующий код из MSVC++:

все они кажутся dwords, таким образом, принимая 4 байта каждый. Так что я вижу, что есть разрыв от hInstance до var_4 4 байта. Что это такое? Я предполагаю, что это обратный адрес, как можно увидеть в Википедии фото?

(Примечание редактора: удалена длинная цитата из ответа Майкла, которая не относится к вопросу, но следующий вопрос был отредактирован):

это потому, что поток вызова функции:

мой вопрос (последний, я надеюсь!) теперь, что именно происходит с момента появления аргументов функции, которую я хочу вызвать, до конца пролога? Я хочу знать, как ebp, esp развиваются во время этих моменты (я уже понял, как работает пролог, я просто хочу знать, что происходит после того, как я нажал аргументы в стеке и перед прологом).

8 ответов:

esp это, как вы говорите, это, в верхней части стека.

большинство прологов функций выглядят примерно так:

тогда позже в функции у вас может быть такой код (предполагая, что обе локальные переменные составляют 4 байта)

для вашего обновленного вопроса отсутствуют две записи в стеке:

это потому, что поток вызова функции:

ESP-это текущий указатель стека, который будет меняться каждый раз, когда слово или адрес нажимается или выскакивает из стека. EBP-это более удобный способ для компилятора отслеживать параметры функции и локальные переменные, чем использовать ESP напрямую.

Как правило (и это может варьироваться от компилятора к компилятору), все аргументы функции помещаются в стек (обычно в обратном порядке, в котором они объявлены в функции прототипа, но это варьируется). Затем вызывается функция, которая помещает обратный адрес (EIP) в стек.

при входе в функцию старое значение EBP помещается в стек, а EBP устанавливается в значение ESP. Затем ESP уменьшается (потому что стек растет вниз в памяти), чтобы выделить пространство для локальных переменных и временных функций функции. С этого момента во время выполнения функции аргументы функции располагаются в стеке с положительным значением смещения от EBP (потому что они были выдвинуты до вызова функции), а локальные переменные расположены на отрицательных смещениях от EBP (потому что они были выделены в стеке после записи функции). Вот почему EBP называется указатель фрейма, потому что он указывает к центру кадр вызова функции.

при выходе все, что должна сделать функция, это установить ESP на значение EBP (которое освобождает локальные переменные от стек, и предоставляет запись EBP в верхней части стека), затем всплывает старое значение EBP из стека, а затем функция возвращает (выталкивая обратный адрес в EIP).

вы все правильно поняли. Указатель стека указывает на верхний элемент стека, а базовый указатель указывает на «предыдущая» вершина стека перед вызовом функции.

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

делать выделение памяти таким образом очень,очень быстро и эффективно.

EDIT: для лучшего описания см. x86 разборка / функции и стековые кадры в WikiBook о сборке x86. Я пытаюсь добавить некоторые сведения, которые могут вас заинтересовать в использовании Visual Studio.

сохранение вызывающего EBP в качестве первой локальной переменной называется стандартным стековым фреймом, и это может использоваться почти для всех соглашений о вызовах в Windows. Существуют различия в том, освобождает ли вызывающий или вызываемый объект переданные параметры и какие параметры передаются в регистрах, но они ортогональны к стандартной задаче кадра стека.

говоря о программах Windows, вы, вероятно, можете использовать Visual Studio для компиляции кода C++. Имейте в виду, что Microsoft использует оптимизацию, называемую пропуском указателя кадра, что делает практически невозможным выполнение обхода стека без использования библиотеки dbghlp и файла PDB для исполняемого файла.

Это опущение указателя кадра означает, что компилятор не сохраняет старый EBP на стандартное место и использует регистр EBP для чего-то еще, поэтому вам трудно найти вызывающий EIP, не зная, сколько места требуется локальным переменным для данной функции. Конечно, Microsoft предоставляет API, который позволяет выполнять Stack-walks даже в этом случае, но поиск базы данных таблиц символов в файлах PDB занимает слишком много времени для некоторых случаев использования.

прежде всего, указатель стека указывает на нижнюю часть стека, так как стеки x86 строятся из высоких значений адресов в более низкие значения адресов. Указатель стека-это точка, в которой при следующем вызове push (или вызове) будет размещено следующее значение. Это операция эквивалентна оператору C/C++:

базовый указатель текущего кадра. ebp обычно указывает на ваш обратный адрес. ebp+4 указывает на первый параметр вашей функции (или это значение класса метод.) ebp-4 указывает на первую локальную переменную вашей функции, обычно старое значение ebp, поэтому вы можете восстановить предыдущий указатель кадра.

давно я не занимался ассемблерным программированием, но этой ссылке может быть полезно.

процессор имеет набор регистров, которые используются для хранения данных. Некоторые из них являются прямыми значениями, в то время как другие указывают на область в ОЗУ. Регистры, как правило, используются для определенных конкретных действий, и каждый операнд в сборке потребует определенного количества данных в конкретных регистрах.

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

базовые регистры или сегментные регистры просто указывают на адресное пространство большого объема данных. В сочетании со вторым регистратором базовый указатель будет разделите память на огромные блоки, в то время как второй регистр будет указывать на элемент внутри этого блока. Базовые указатели для этого указывают на базу блоков данных.

имейте в виду, что сборка очень специфична для ЦП. Страница, на которую я ссылался, содержит информацию о различных типах процессоров.

Edit Да, это в основном неправильно. Он описывает что-то совершенно другое в случае, если кто-то заинтересован 🙂

да, указатель стека указывает на верхнюю часть стека (будь то первое пустое место стека или последнее полное, в котором я не уверен). Базовый указатель указывает на место в памяти выполняемой инструкции. Это на уровне опкодов-самая основная инструкция, которую вы можете получить на компьютере. Каждый код операции и его параметры хранятся в памяти. Одна строка C или C++ или C# может быть переведена в один код операции или последовательность из двух или более в зависимости от того, насколько она сложна. Они записываются в память программы последовательно и выполняются. В обычных условиях базовый указатель увеличивается на одну инструкцию. Для управления программой (GOTO, IF и т. д.) Он может быть увеличен несколько раз или просто заменен следующим адресом памяти.

в этом контексте, функции хранятся в память программы по определенному адресу. Когда функция вызывается, определенная информация помещается в стек, который позволяет программе найти ее обратно туда, откуда была вызвана функция, а также параметры функции, затем адрес функции в памяти программы помещается в базовый указатель. На следующем такте компьютер начинает выполнять инструкции с этого адреса памяти. Затем в какой-то момент он вернется в ячейку памяти после инструкции, что вызывается функция и продолжается оттуда.

esp означает «расширенный указатель стека». ebp для»чего-то базового указателя». и eip для»чего-то указателя инструкции». Указатель стека указывает на адрес смещения сегмента стека. Базовый указатель указывает на адрес смещения дополнительного сегмента. Указатель инструкции указывает на адрес смещения сегмента кода. Теперь о сегментах. они представляют собой небольшие 64KB подразделения области памяти процессоров. Этот процесс известен как сегментация памяти. Я надеюсь, что это сообщение было полезно.

Источник

Путешествие по Стеку. Часть 1

Stack pointer что это. image loader. Stack pointer что это фото. Stack pointer что это-image loader. картинка Stack pointer что это. картинка image loader

В предыдущих материалах мы рассмотрели размещение программы в памяти – одну из центральных концепций, касающихся выполнения программ на компьютерах. Теперь обратимся к стеку вызовов – рабочей лошадке большинства языков программирования и виртуальных машин. Нас ожидает знакомство с удивительными вещами вроде функций-замыканий, переполнений буфера и рекурсии. Однако всему свое время – в начале нужно составить базовое представление о том, как работает стек.

Стек имеет такое важное значение, потому что благодаря ему любая функция «знает» куда возвращать управление после завершения; функция же, в свою очередь — это базовый строительный блок программы. Вообще, программы внутренне устроены довольно просто. Программа состоит из функций, функции могут вызывать другие функции, в процессе своей работы любая функция помещает данные в стек и снимает их оттуда. Если нужно, чтобы данные продолжили существовать после завершения функции, то место под них выделяется не в стеке, а в куче. Вышесказанное в равной степени относится как к программам, написанным на относительно низкоуровневом C, так и к интерпретируемым языкам вроде JavaScript и C#. Знание данных вещей обязательно пригодится — и если придется отлаживать программу, и если доведется заниматься тонкой подстройкой производительности, да и просто для того, чтобы понимать, что же там, все-таки творится внутри программы.

Итак, начнем. Как только мы вызываем функцию, в стеке для нее создается стековый кадр. Стековый кадр содержит локальные переменные, а также аргументы, которые были переданы вызывающей функцией. Помимо этого кадр содержит служебную информацию, которая используется вызванной функцией, чтобы в нужный момент возвратить управление вызвавшей функции. Точное содержание стека и схема его размещения в памяти могут быть разными в зависимости от процессорной архитектуры и используемой конвенции вызова. В данной статье мы рассматриваем стек на архитектуре x86 с конвенцией вызова, принятой в языке C (cdecl). На рисунке вверху изображен стековый кадр, разместившийся у верхушки стека.

Сразу бросаются в глаза три процессорных регистра. Указатель стека, esp, предназначается для того, чтобы указывать на верхушку стека. Вплотную к верхуше всегда находится объект, который был добавлен в стек, но еще оттуда не снят. Точно также в реальной жизни обстоят дела со стопкой тарелок или пачкой 100-долларовых банкнот.

Хранимый в регистре esp адрес изменяется по мере того, как объекты добавляются и снимаются со стека, однако он всегда указывает на последний добавленный и еще не снятый со стека объект. Многие процессорные инструкции изменяют значение регистра esp как побочный результат своего выполнения. Реализовать работу со стеком без регистра esp было бы проблематично.

В случае с процессорами Intel, ровно как и со многими другими архитетурами, стек растет в направлении меньших адресов памяти. Поэтому верхушка, в данном случае, соответствует наименьшему адресу в стеке, по которому хранятся валидные используемые данные: в нашем случае это переменная local_buffer. Думаю, должно быть понятно, что означает стрелка от esp к local_buffer. Здесь все, как говорится, по делу – стрелка указывает точно на первый байт, занимаемый local_buffer, и это соответствует тому адресу, который хранится в регистре esp.

Далее на очереди еще один регистр, используемый для отслеживания позиций в стеке – регистр ebpбазовый указатель или указатель базы стекового кадра. Данный регистр предназначен для того, чтобы указывать на позицию в стековом кадре. Благодаря регистру ebp текущая функция всегда имеет своего рода точку отсчёта для доступа к аргументам и локальным переменным. Хранимый в регистре адрес изменяется, когда функция начинает или прекращает выполнение. Мы можем довольно просто адресовать любой объект в стековом кадре как смещение относительно ebp, что и показано на рисунке.

В отличии от esp, манипуляции с регистром ebp осуществляется в основном самой программой, а не процессором. Иногда можно добиться выигрыша в производительности просто отказавшись от страндартного использования регистра ebp – за это отвечают некоторые флаги компилятора. Ядро Linux – пример того, где используется такой прием.

Наконец, регистр eax традиционно используется для хранения данных, возвращаемых вызвавшей функции — это высказывание справедливо для большинства поддерживаемых в языке C типов.

Теперь давайте разберем данные, содержащиеся в стековом кадре. Рисунок показывает точное побайтовое содержимое кадра, c направлением роста адресов слево-направо – это то, что мы обычно видим в отладчике. А вот и сам рисунок:

Stack pointer что это. image loader. Stack pointer что это фото. Stack pointer что это-image loader. картинка Stack pointer что это. картинка image loader

Локальная переменная local_buffer – это массив байт, представляющий собой нуль-терминированную ASCII-строку; такие строки — неизменный атрибут всех программ на C. Размер строки — 7 байт, и, скорее всего, она была получена в результате клавиатурного ввода или чтения из файла. В нашем массиве может храниться 8 байт и, следовательно, один байт остается неиспользуемым. Значение этого байта неизвестно. Дело в том, что, данные то и дело добавлются и снимаются со стека, и в этом «бесконечном танце операции добавления и снятия» никогда нельзя знать заранее, что содержит память, пока не осуществишь в нее запись. Компилятор языка C не обременяет себя тем, чтобы иницилизировать стековый кадр нулями. Поэтому содержащиеся там данные заранее неизвестны и являются в некоторой степени случайными. Уж сколько крови попило такое поведение компилятора у программистов!

Идем далее. local1 – 4-байтовое целое число, и на рисунке видно содержимое каждого байта. Кажется, что это большое число – только взгляните на все эти нули после восьмерки, однако здесь наша интуиция сослужила нам дурную службу.

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

Неплохо знать о том, что вся эта «остроконечная / тупоконечная» терминология восходит к произведению Джонатана Свифта «Путешествия Гулливера». Подобно тому, как жители Лилипутии чистили яйцо с острого конца, процессоры Intel тоже обрабатывают числа начиная с младшего байта.

Таким образом, переменная local1 в действительности хранит число 8 (да-да, прям как количество щупалец у осьминога). Что касается param1, то там во втором от начала октете изображена двойка, поэтому в результате получаем число 2 * 256 = 512 (мы умножаем на 256, потому что каждый октет – это диапазон от 0 до 255). param2 хранит число 1 * 256 * 256 = 65536.

Служебная информация стекового кадра включает в себя два компонента: адрес стекового кадра вызвавшей функции (на рисунке — saved ebp) и адрес инструкции, куда необходимо передать управление по завершении данной функции (на рисунке – return address). Эта информация делает возможным возвращение управления, и следовательно, дальнейшее выполнение программы как будто никакого вызова и не было.

Теперь давайте рассмотрим процесс «рождения» стекового кадра. Стек растет не в том направлении, которое обычно ожидают увидеть, и сначала это может сбивать с толку. Например, чтобы увеличить стек на 8 байт, программист вычитает 8 из значения, хранимого в регистре esp. Вычитание – странный способ что-либо увеличить. Забавно, не правда ли!

Возьмем для примера простенькую программу на C:

Stack pointer что это. image loader. Stack pointer что это фото. Stack pointer что это-image loader. картинка Stack pointer что это. картинка image loader

Предположим, программу запустили без параметров в командной строке. При выполнении «сишной» программы в Linux, первым делом управление получает код, содержащийся в стандартной библиотеке C. Этот код вызовет функцию main() нашей программы, и, в данном случае, переменная argc будет равна 0 (на самом деле, переменная будет равна «1», что соответствует параметру — названию, под которым запущена программа, но давайте для простоты это момент сейчас опустим). При вызове функции main() происходит следующее:

Stack pointer что это. image loader. Stack pointer что это фото. Stack pointer что это-image loader. картинка Stack pointer что это. картинка image loader

Шаг 2 и 3, а также 4 (описан ниже) соответствуют последовательности инструкций, которая называется «прологом» и встречается практически в любой функции: текущее значение регистра ebp помещается в стек, затем значение регистра esp копируется в регистр ebp, что фактически приводит к созданию нового стекового кадра. Пролог функции main() такой же, как и других функций, с той лишь разницей, что при начале выполнения программы регистр ebp содержит нули.

Если взглянуть на то, что располагается в стеке под argc, то будут видны еще некоторые данные – указатель на строку-название, под которым программа была запущена, указатели на строки-параметры, переданные через командную строку (традиционный C-массив argv), а также указатели на переменные среды и непосредствено сами эти переменные. Однако, на данном этапе нам это не особо важно, так что продолжаем двигаться по направлению к вызову функции add():

Stack pointer что это. image loader. Stack pointer что это фото. Stack pointer что это-image loader. картинка Stack pointer что это. картинка image loader

Функция main() сначала вычетает 12 из текущего значения в регистре esp для выделения нужного ей места и затем присваивает значения переменным a и b. Значения, хранимые в памяти, изображены на рисунке в шестнадцатеричной форме и с прямым порядком байтов – как и в любом отладчике. После присвоения значений, функция main() вызывает функцию add(), и та начинает выполняться:

Stack pointer что это. image loader. Stack pointer что это фото. Stack pointer что это-image loader. картинка Stack pointer что это. картинка image loader

Чем дальше, тем интересней! Перед нами еще один пролог, однако теперь уже четко видно как последовательность стековых кадров в стеке оказывается организованной в связный список, и регистр ebp хранит ссылку на первый элемент этого списка. Вот с опорой на это и реализованы трассировка стека в отладчиках и Exception-объекты высокоуровневых языков. Обратим внимание на типичную для начала выполнения функции ситуацию, когда регистры ebp и esp указывают в одно и то же место. И еще раз вспомним, что для наращивания стека осуществляется вычитание из значения, хранящегося в регистре esp.

Важно заметить следующее — при копировании данных из регистра ebp в память происходит непонятное на первый взгляд изменение порядка хранения байтов. Дело в том, что для регистров такого понятия как «порядок байтов» не существует. Иными словами, рассматривая регистр, мы не можем говорить о том, что в нем есть «старшие или младшие адреса». Поэтому отладчики показывают значения, хранимые в регистрах, в наиболее удобном для человеческого восприятия виде: от более значимых к менее значимым цифрам. Таким образом, имея стандартную нотацию «слева-направо» и «little-endian» машину, создается обманчивое впечатление, что в результате операции копирования из регистра в память байты поменяли порядок на обратный. Я хотел, чтобы картина, показанная на рисунках была максимально приближена к реальности – отсюда и такие рисунки.

Теперь, когда самая сложная часть у нас позади, осуществляем сложение:

Stack pointer что это. image loader. Stack pointer что это фото. Stack pointer что это-image loader. картинка Stack pointer что это. картинка image loader

Здесь у нас появляется неизвестный регистр, чтобы помочь со сложением, но в целом ничего особенного или удивительного. Функция add() выполняет вою работу и, начиная с этого момента все действия в стеке будут осуществляться в обратном порядке. Но об этом расскажем как-нибудь в другой раз.

Все, кто дочитал до этих строк, заслуживает подарок за стойкость, поэтому я с огромной гиковской гордостью презентую Вам вот эту единую схемку, на которой изображены все вышеописанные шаги.

Не так уж все и сложно, стоит только разложить все по полочкам. Кстати, маленькие квадратики очень сильно помогают понимаю. Без «маленьких квадратиков» в информатике вообще никуда. Надеюсь, мои рисунки позволили составить ясную картину происходящего, на которой интуитивно просто показан и рост стека, и изменения содержимого памяти. При ближайшем рассмотрении, наше программное обеспечение не так уж и сильно отличается от простой машины Тьюринга.

На этом завершается первая часть нашего путешествия по стеку. В будущих статьях нас ждут новые погружения в «байтовые» дебри, после чего посмотрим, что же на этом фундаменте способны выстроить высокоуровневые языки программирования. Увидимся на следующей неделе.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *