Можно ли создавать новые лексические символы в других контекстах во время выполнения?

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

Фрейм стека для каждой подпрограммы делится на три части: функциональные параметры, обратный указатель на предыдущий стек кадр и локальные переменные.

Часть 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 будет выталкивать # слова (или # байты, я не могу вспомнить, какой) из стека, когда он возвращается, тем самым удаляя параметры из стека. Если я правильно помню, это стиль, используемый Паскалем.

Это долго, но я надеюсь, что это поможет вам лучше понять стековые кадры.

5
задан Kaiepi 18 March 2019 в 19:02
поделиться

2 ответа

Я собираюсь сказать «Нет».

(Я обычно учусь сожалеть о том, что делал это с P6, но что за эй.)

Моим основным доказательством являются комментарии типа «набор символов в лексической области неизменен после времени компиляции» [ 110].

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

Когда вы закончите бросать, запечатайте сумку, а затем посетите IRC-канал freenode # perl6-dev , где тусуются настоящие эксперты в вещах, связанных с кишками. (Я думаю, вы знаете об этом, но подумал, что включу его в этот ответ для потомков и потому, что у меня плохое чувство юмора.)

0
ответ дан raiph 18 March 2019 в 19:02
поделиться

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

0
ответ дан jjmerelo 18 March 2019 в 19:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: