@Pyrolistical
, так как исходный первый статический класс myclass не полностью построен ... результат i get is
null null testInitialize.MyObject@70f9f9d8 null
Кадр стека x86-32 создается путем выполнения
function_start:
push ebp
mov ebp, esp
, поэтому он доступен через ebp и выглядит как
ebp+00 (current_frame) : prev_frame
ebp+04 : return_address
....
prev_frame : prev_prev_frame
prev_frame+04 : prev_return_address
. Есть некоторые преимущества использования ebp для стека кадры с помощью команды сборки, поэтому для доступа к файлам и локалям обычно используется регистр ebp.
Каждая подпрограмма использует часть стека, и мы называем ее фреймом стека. Хотя программист ассемблера не вынужден следовать следующему стилю, он рекомендуется в качестве хорошей практики.
Фрейм стека для каждой подпрограммы делится на три части: функциональные параметры, обратный указатель на предыдущий стек кадр и локальные переменные.
Часть 1: Параметры функции
Эта часть фрейма стека подпрограммы настроена вызывающим. Используя команду «push», вызывающий пользователь выталкивает параметры в стек. Различные языки могут подталкивать параметры в разных порядках. C, если я правильно помню, толкает их справа налево. То есть, если вы вызываете ...
foo (a, b, c);
Вызывающий преобразует это значение в ...
push c
push b
push a
call foo
Поскольку каждый элемент помещается в стек, стек растет. То есть регистр указателя стека уменьшается на четыре (4) байта (в 32-битном режиме), и элемент копируется в ячейку памяти, на которую указывает регистр стека. Обратите внимание, что команда «вызов» будет неявно нажать адрес возврата в стеке. Очистка параметров будет рассмотрена в части 5.
Часть 2: указатель обратного отсчета стека
На данный момент выдается инструкция «вызов», и мы сейчас находимся в начало вызванной процедуры. Если мы хотим получить доступ к нашим параметрам, мы можем получить к ним доступ, как ...
[esp + 0] - return address
[esp + 4] - parameter 'a'
[esp + 8] - parameter 'b'
[esp + 12] - parameter 'c'
Однако это может стать неуклюжим после того, как мы выберем место для локальных переменных и прочее. Таким образом, мы используем регистр указателя стека в дополнение к регистру указателя стека. Однако мы хотим, чтобы регистр стека-указателя был установлен на наш текущий кадр, а не на предыдущую функцию. Таким образом, мы сохраняем старый в стеке (который изменяет смещения параметров в стеке), а затем копируют текущий регистр указателя стека в регистр указателя стека.
push ebp ; save previous stackbase-pointer register
mov ebp, esp ; ebp = esp
Иногда вы может видеть это, используя только инструкцию «ENTER».
Часть 3: Резервное пространство для локальных переменных
Локальные переменные сохраняются в стеке. Так как стек растет, мы вычитаем несколько байтов (достаточно для хранения наших локальных переменных):
sub esp, n_bytes ; n_bytes = number of bytes required for local variables
Часть 4: Объединим все это. Доступ к параметрам осуществляется с помощью регистра указателя стека ...
[ebp + 16] - parameter 'c'
[ebp + 12] - parameter 'b'
[ebp + 8] - parameter 'a'
[ebp + 4] - return address
[ebp + 0] - saved stackbase-pointer register
Доступ к локальным переменным осуществляется с помощью регистра указателя стека ...
[esp + (# - 4)] - top of local variables section
[esp + 0] - bottom of local variables section
Часть 5: Очистка стоп-кадра
Когда мы покидаем подпрограмму, необходимо очистить стековый фрейм.
mov esp, ebp ; undo the carving of space for the local variables
pop ebp ; restore the previous stackbase-pointer register
Иногда вы можете увидеть инструкцию «LEAVE», заменяющую эти две команды.
В зависимости от языка, который вы использовали, вы можете увидеть одну из двух форм инструкции «RET».
ret
ret <some #>
Какой бы выбор ни выбрали, будет зависеть от выбора языка (или стиля, который вы хотите следовать если писать на ассемблере). Первый случай указывает на то, что вызывающий отвечает за удаление параметров из стека (с примером foo (a, b, c) он будет делать это через ... add esp, 12), и это способ «C» Это. Второй случай указывает, что команда return будет выталкивать # слова (или # байты, я не могу вспомнить, какой) из стека, когда он возвращается, тем самым удаляя параметры из стека. Если я правильно помню, это стиль, используемый Паскалем.
Это долго, но я надеюсь, что это поможет вам лучше понять стековые кадры.
Кадр стека x86 может использоваться компиляторами (в зависимости от компилятора) для передачи параметров (или указателей на параметры) и возвращаемых значений. См. этот
Это зависит от используемой операционной системы и языка. Причина в том, что в ASM нет общего формата для стека, единственное, что делает стек в ASM, - это сохранить обратный адрес при выполнении подпрограммы перехода. При выполнении функции return-from-sub адрес выбирается из стека и помещается в программу-счетчик (ячейка памяти, в которой должна быть записана следующая инструкция выполнения ЦП)
Вам нужно будет проконсультироваться с вашим документацию для используемого компилятора.