Возврат значения на ассемблере x86 - PullRequest
1 голос
/ 20 апреля 2019

В настоящее время я изучаю язык ассемблера x86 (я в начале курса), и у меня возникают некоторые проблемы с пониманием работы стека в одном конкретном случае.

Допустим, у меня есть этокод:

double(entier n) { return n + n; }

Я пытался преобразовать его в код x86, и я получил следующее:

push ebp #save old pointer stack
mov ebp, esp #put new pointer stack
mov ebx, dword[ebp + 8] #get argument n and put it in ebx
add ebx, dword[ebp + 8] #add n to ebx 

Но потом я был полностью заблокирован и не мог найти, каквернуть значение ebx.Я нашел решение в Интернете, которое было следующим:

mov [ebp + 12], ebx
pop ebp
ret
pop ebp
ret

Я не понимаю, как это работает.Разве ebp+12 не является значением второго аргумента?(В моем случае его нет).Pop используется для перемещения указателя esp, но зачем нам в этом случае 2 pop и 2 return?Это только для удаления значения, которое использовалось во время объявления функции?

1 Ответ

4 голосов
/ 20 апреля 2019

Поскольку кажется, что это вас полностью смущает, позвольте мне показать вам, как это сделать:

double: push ebp           ; establish...
        mov ebp, esp       ; ...stack frame

        mov eax, [ebp + 8] ; load argument from stack into eax
        add eax, eax       ; add it to itself

        leave              ; tear down the stack frame
        ret                ; return to the caller

Обратите внимание, что я выбрал eax вместо ebx для регистра.Это происходит по двум причинам:

  • eax является регистром, сохраненным вызывающим абонентом (это означает, что вызывающий должен позаботиться о сохранении своего значения при желании), тогда как ebx является регистром, сохраненным вызывающим абонентом (Это означает, что вызываемый объект, т. е. double, должен сохранять свое значение).Если мы хотели использовать ebx, нам нужно было сохранить и восстановить его старое значение.Если вместо этого мы используем регистр, сохраненный вызывающей стороной, такой как eax, мы можем избежать этого.
  • eax - это регистр, в котором по соглашению найдено возвращаемое значение.Вызывающая сторона примет значение eax в качестве возвращаемого значения.

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


Для будущих вопросов вместеВ этих строках я советую вам проверить вывод компилятора C с включенными оптимизациями.Компилятор C очень хорош в генерации ассемблера и редко допускает ошибки.В UNIX-подобных системах, таких как Linux, вы можете использовать опцию -S для генерации кода сборки.Для gcc я советую вам набрать

gcc -m32 -O3 -masm=intel -fno-omit-frame-pointer -S -o- source.c

, чтобы на терминале был напечатан код сборки для source.c в синтаксисе Intel, который, как вы думаете, использует стиль сборки.

См. Также Как удалить «шум» из выходных данных сборки GCC / clang? для получения более подробной информации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...