Ошибка сегментации Push/Pop в сборке x86
Я использую elf64 для компиляции моего кода сборки x86: у меня есть эта подпрограмма:
printNumber:
mov EAX, EDX ; EDX contain some value like "35"
mov ESI, 10 ; to divide by 10
MOV ECX,0 ; counter
whileDiv:
cmp EAX, 0
je endWhileDiv
xor rdx, rdx ; clean RDX
idiv ESI ; EAX=EAX/10 and EDX = EAX%10
push rdx ; this line generate a segmentation fault
add ECX, 1; count how many items i has added into stack
jmp whileDiv
endWhileDiv:
ret
Я пытаюсь вставить все цифры числа в мой стек, используя push, но я получаю ошибку сегментации. Когда я комментирую эту строку:
push rdx ; this line generate a segmentation fault
Я больше не буду принимать "Ошибка сегментации"
Я использую "push rdx" вместо "push EDX", потому что я использую 64-битный режим в NASM, и когда я пытаюсь использовать: "push EDX", я получаю эту ошибку: "инструкция не поддерживается в 64-битной среде Режим"
Пожалуйста, кто-нибудь может подсказать, почему это происходит и как решить?
PS: извините за мой плохой английский
3 ответа
Я вижу толчок rdx, но нигде нет популярности rdx. Вы продолжаете помещать значения в стек, а когда вы достигаете RET, вы возвращаетесь к адресу, который ранее был содержимым RDX.
Разве это не должно быть "PUSH EDX" вместо "PUSH RDX"? Или, может быть, PUSH dword ptr 0/PUSH EDX, если вам действительно нужно использовать 64-битную версию? Хотите знать, может быть, это в конечном итоге не выравнивается и не нравится? Предыдущие режимы x86 не заботятся о выравнивании, но, возможно, это касается инструкций x64?
Инструкция
push rdx;
Сам по себе может вызвать ошибку сегментации только в довольно редких случаях: когда у вас заканчивается стек или когда вы перепутались с (E)SP. Поскольку вы можете запустить этот код, я не думаю, что вы сделали второй, а первый довольно нереалистичен, если это все, что делает ваше приложение. Но Майкл выше указывал на правильное направление: это не инструкция толчка, которая вызывает ошибку сегментации, а отсутствующие всплывающие окна перед ret
, В конце вашей функции стек должен содержать ровно столько же элементов, что и в начале, либо инструкция ret прочитает все, что находится внизу стека, и попытается использовать его в качестве адреса возврата -> bang.
Вы не можете использовать стек для возврата значений таким способом. Вы (например) нуждаетесь в вызывающей функции, чтобы выделить память для возвращаемых данных и предоставить ее адрес в качестве аргумента. Читайте о соглашениях о вызовах и передаче аргументов на ассемблере.