Сборка-push-регистр RAX не то же самое, когда я извлекаю его из стека?

В настоящее время я пишу сборку NASM на 64-битной машине, чтобы распечатать факториал данного ввода, а затем вернуть ввод. Программа правильно работает для распечатки факториальных значений, но возвращаемое значение не возвращает ввод. Да, код ужасен, и я не хочу, чтобы вы просто переписали его целиком. (Это моя домашняя работа.) Я просто хочу, чтобы кто-нибудь объяснил, почему мой регистр возврата (rax) НЕ сохраняет значение, которое у него было с самого начала.

extern read_input
extern print_int
call read_input

push rax   ;save n
mov rcx, 1 ;counter
push rcx   ;save counter
push rdi   ;save print int

jmp test

print:
pop rdi
imul rdi, rcx ;multiply by current counter
push rdi      ;save our multiplication factor
call print_int

pop rdi
pop rcx 
pop rax    ;restore trashed variables
add rcx, 1 ;increment counter by 1
push rax   ;push stuff back on stack
push rcx
push rdi

jmp test

test:
cmp rcx, rax
jle print

pop rax 
pop rcx 
pop rdi ;clear stack
ret

Выход:

Please enter an input value:
read_input> Returning 4 (0x4)
Printing integer 1 (0x1)
Printing integer 2 (0x2)
Printing integer 6 (0x6)
Printing integer 24 (0x18)
Program complete.  Return 24 (0x18)

Я хочу, чтобы он возвращал мой ввод, который в данном случае будет 4.

Любое понимание будет оценено.


person derp    schedule 29.09.2012    source источник
comment
Спасибо, что не используете устаревший тег домашнего задания — он избавляет нас от этих аргументов.   -  person Linuxios    schedule 29.09.2012
comment
Я не знал, что есть даже пометка о домашнем задании или что это табу. Теперь я знаю, наверное?   -  person derp    schedule 29.09.2012
comment
@derp Опоздал примерно на год, но да.   -  person Qix - MONICA WAS MISTREATED    schedule 22.07.2014


Ответы (2)


Порядок толчков и хлопков неправильный.

Толчки:

push rax   ;save n
mov rcx, 1 ;counter
push rcx   ;save counter
push rdi   ;save print int
...
push rax   ;push stuff back on stack
push rcx
push rdi

Попсы:

pop rdi
pop rcx 
pop rax    ;restore trashed variables
...
pop rax 
pop rcx 
pop rdi ;clear stack
ret

В конце rax и rdi меняются местами, упс.

person Alexey Frunze    schedule 29.09.2012

Дело в том, что места в стеке не имеют имен или идентификаторов. Вы должны нажать и поп в том же порядке. Когда вы говорите pop rax, процессор не спрашивает: «Где последняя запись, сделанная push rax?», а скорее спрашивает: «Где последняя запись, которую нужно отправить?». Итак, ваш стек выглядит так (при условии, что rax 1, rbx 2, rcx 3):

0x0001 #push rax
0x0002 #push rbx
0x0003 #push rcx
  |
  \----- This is the value retrieved by pop rax

Просто следуйте этому правилу: всегда нажимайте элементы в том же порядке, в котором вы их извлекаете, если вы явно не пытаетесь переключить значения (что лучше сделать с помощью xchg).

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

push 0x0000000000000000 ;New value for rflags
popf ;Pop it into rflags
person Linuxios    schedule 29.09.2012