Rob Philpott Ответов: 2

Почему мой стек странный?


Вот короткая программа....
int main()
{
	_asm
	{
		push al;
		pop al;
		pop al;
	};
    return 0;
}

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

Похоже, что толчок фактически перемещает указатель стека на 4 байта, в то время как pop только перемещает его обратно на 2, но регистр должен быть одним байтом, нижней половиной 16-битной вещи. Что происходит?

Что я уже пробовал:

Ну, я попробовал немного подумать об этом в своей голове, но это не помогло.

Dave Kreskowiak

Отличный вопрос, чтобы заставить людей задуматься.

Я уже собирался вмешаться с криком "проверь .ASM log вашей компиляции или окна дизассемблера, чтобы увидеть, что он действительно делает", когда я обнаружил, что вы сделали этот самый комментарий 10 минут назад.

[no name]

1

2 Ответов

Рейтинг:
1

Patrice T

Цитата:
Похоже, что толчок фактически перемещает указатель стека на 4 байта, в то время как pop только перемещает его обратно на 2, но регистр должен быть одним байтом, нижней половиной 16-битной вещи. Что происходит?

ООО Регистр 1 байт, так толкать и хлопок перемещаем указатель стека 1-байтовый.
По замыслу, указатель стека перемещается соответственно размеру выбранного вами регистра. Ваша обязанность-сделать все операции стека согласованными.

Используйте отладчик, чтобы точно видеть, что происходит.
Отладчик - Википедия, свободная энциклопедия[^]

Освоение отладки в Visual Studio 2010 - руководство для начинающих[^]
Базовая отладка с помощью Visual Studio 2010 - YouTube[^]


Rob Philpott

Я согласен, но это не то, что я вижу (в отладчике).

Например, для пуш/поп еах вот несколько значений ЭСП перед тужиться, прежде чем поп-и после поп:

0x39f7b0
0x39f7ac
0x39f7b0

Именно то, что вы ожидаете, 4-байтовое движение в каждую сторону для 4-байтового регистра. Для push/pop AX я получил:

0x3ffc60
0x3ffc5e
0x3ffc60

Опять же, точно так же, как вы ожидали бы с 2-байтовым движением для 2-байтового регистра. Но когда я делаю это только для Эла, я получаю это:

0x3ef8c8
0x3ef8c4
0x3ef8c6

Таким образом, движение 4 байта для push и 2 байта для pop, после чего Visual Studio полностью расстраивается, потому что стек неправильный.

Patrice T

Тогда он не может справиться с этим совершенно законным кодексом:

	_asm	{		push al;		push bl;		pop cx;	};

Ошибка в процессоре или VS ?

Rob Philpott

Ассемблер, я думаю. Мне просто пришло в голову проверить окно разборки, и оно показывает это:

толкай ал;
000C16A0 push eax
поп ООО;
000C16A3 поп топор

так нажми Аль =&ГТ; нажать eax и поп АЛ =&ГТ; поп-топор. Это VS2015 C++ в блоке asm.

Patrice T

Тогда вы знаете причину :)

[no name]

1

Рейтинг:
0

OriginalGriff

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

Что касается размера, то при добавлении или удалении любого элемента из стека в машинном коде используется одинаковое количество пространства - машинное слово, которое, скорее всего, будет 16, 32 или 64 бита. Если бы это было не так, то стек оказался бы по нечетным адресам, что является плохой идеей по техническим причинам.
Я удивлен, что "push al" вообще работал - машинный код, который он генерирует, почти наверняка будет "push ax", чтобы избежать нечетных адресов.


Rob Philpott

Да, это очень странно, если вы спросите меня. Если я нажму, а потом хлопну EAX, все будет в порядке. Если я толкаю, то поп-топор тоже все в порядке, но когда вы спускаетесь к АЛУ, толчок и поп перемещают указатель стека на разные суммы, ни то, ни другое, чего я ожидал бы. И я не думаю, что это связано с выравниванием слов.

Я здесь валяю дурака, единственное программирование на ассемблере, которым я всерьез занимался, - это на ARM, где процессор-это хорошо организованная вещь красоты, а не какой-то транзисторный эквивалент спальни подростка с X86, нарисованным на двери.

Это компилятор, которого я жалею...

Patrice T

"Я удивлен, что "push al" вообще работал - машинный код, который он генерирует, почти наверняка будет "push ax", чтобы избежать нечетных адресов."
Нет, это устаревшая совместимость, у процессора нет выбора, даже если это потребует дополнительной работы по обработке несогласованных данных.

[no name]

1