Сборка с плавающей запятой на процессоре Intel

Я изучал, как операции с плавающей запятой выполняются на 32-битной машине Intel. Я разобрал следующие строки кода C, чтобы понять, как компилятор транслирует эти строки при ассемблере.

a = 13;
b = 5;
d = (float) a / (float) b;

А вот дизассемблированная версия кода, показанного выше:

mov    DWORD PTR [ebp-0x10],0xd
mov    DWORD PTR [ebp-0x14],0x5
fild   DWORD PTR [ebp-0x10]
fild   DWORD PTR [ebp-0x14]
fdivrp st(1),st
fstp   DWORD PTR [ebp-0x18]

Что меня смущает, так это инструкции fdivrp и fstp. Из того, что я прочитал, приведенный выше код сохранит результат деления с плавающей запятой в регистре st (1), а затем вытолкнет вершину стека, сделав st (1) вершиной, а не st (0). Однако следующая инструкция fstp сохраняет содержимое st(0) в ячейку памяти, на которую указывает адрес ebp-0x18, а затем выталкивает стек, делая st(1) вершиной. Я считаю, что неправильно понял документы о том, как работают эти инструкции, поскольку мое понимание не сохранит результат в памяти. Буду признателен, если кто-нибудь объяснит, как именно работают эти 2 инструкции.


person MykelXIII    schedule 27.10.2015    source источник
comment
Вершина стека всегда называется st(0).   -  person apokryfos    schedule 27.10.2015
comment
stackoverflow.com/tags/x86/info содержит ссылку на ray.masmcode.com/tutorial/index.html, который должен охватывать все. Если вам не приходится часто иметь дело с кодом x87, я бы рекомендовал не тратить на него время, за исключением тех случаев, когда он возникает на практике. x87 устарел, за исключением того, что 32-битный ABI по-прежнему возвращает значения FP в st(0). 64-битный ABI использует регистры SSE для передачи/возврата чисел с плавающей запятой и двойных чисел. 32-битный код можно скомпилировать для использования SSE/SSE2, если вы не возражаете против нарушения совместимости с оборудованием 13-летней давности (AMD Athlon XP был последним процессором, в котором не было SSE2).   -  person Peter Cordes    schedule 28.10.2015
comment
Питер, я вижу, вы регулярно ссылаетесь на 32-битный ABI и 64-битный ABI. Имейте в виду, что существуют разные ABI для разных ОС, и не совсем понятно, какую из них вы имеете в виду, вероятно, Linux или BDS? Обратите внимание, что в 32-битной Windows код x87 вовсе не так устарел.   -  person Rudy Velthuis    schedule 28.10.2015


Ответы (1)


Регистры с плавающей запятой всегда адресуются относительно текущей вершины стека. Таким образом, st(0) всегда является вершиной стека. fdivrp st(1), st помещает результат в st(1), а затем сразу же извлекает st(0), поэтому стек содержит только один элемент, который является новым st(0), содержащим результат. fstp записывает его в память и удаляет из стека fpu, оставляя его пустым.

person Jester    schedule 27.10.2015
comment
Означает ли это, что fdivrp st(1), st извлекает st1 из st0? В документах указано, что для извлечения стека регистров процессор помечает регистр ST(0) как пустой и увеличивает указатель стека (TOP) на 1. Мне трудно понять эту фразу. - person MykelXIII; 27.10.2015
comment
При извлечении стек TOP изменяется, и, поскольку индексация регистров относится к TOP, физический регистр, который ранее назывался st(1), становится st(0). Нет никакого движения данных. - person Jester; 27.10.2015