2012-06-24 2 views
2

В последние дни я играл с C++, ASM и встроенным ASM. Я знаю, как обращаться к основным переменным в памяти и тому подобным вещам. Теперь я пытаюсь работать с числами с плавающей запятой в ASM. я разобрал этот код:номера с плавающей запятой в ASM

float A = 0.058; 

и у меня есть этот результат:

fld   dword ptr ds:[00415744h] 
fstp  dword ptr [ebp-8] 

Но я не понимаю, этот код. Я искал в Google, но я не нашел ничего полезного для меня. Может ли кто-нибудь объяснить мне реальные цифры в ASM и может кто-нибудь объяснить мне этот код? Пожалуйста, помогите мне.

+0

Под «реальными числами», вы имеете в виду [литералы] (http://en.wikipedia.org/wiki/Literal_ (computer_programming)), или вы имеете в виду [числа с плавающей запятой] (http://en.wikipedia.org/wiki/Floating_point)? –

+0

о, извините. Номера с плавающей запятой – user35443

+0

Похоже, что x86 (x87) сборка? Может быть полезно пометить его как таковой. – MSalters

ответ

2

Первая строка загружает постоянное значение поплавка 0.058 в стек FPU. Вторая строка копирует верхнюю часть стека FPU в стек процессора, адресованный ebp-8.

Здесь вы можете прочитать инструкции FPU: http://maven.smith.edu/~thiebaut/ArtOfAssembly/CH14/CH14-4.html или в любой другой ссылке на Ссылку.

Редактировать.

dword ptr [ebp-8] копирует верхнюю часть стека FPU в локальную переменную DWORD в стеке. Из ссылки на сборку, EBP (базовый указатель): функция Assembly устанавливает базовый указатель равным указателю стека, а затем помещает свои собственные внутренние переменные в стек. С этого момента функция ссылается на ее параметры и переменные относительно базового указателя, а не на указатель стека.

+0

Хорошо. Благодарю. Еще один маленький вопрос: почему есть ebp-8? float - dword (4 байта = 32 бита). Так как же оно может быть в памяти? – user35443

+0

... и эта ссылка не работает .... (GC) – user35443

+0

См. Отредактированный ответ. Ссылка URL исправлена. –

4

Это то, что компилятор сделал с кодом:

Компилятор признан «0,058», как с плавающей точкой буквальным. Он проанализировал строку для вычисления представленного значения и для кодирования этого значения в виде значения с плавающей запятой двойной точности. Затем он признал, что вы присваиваете это значение двойной точности объекту с одной точностью (float A, а не double A), поэтому ему не нужно полное значение двойной точности. Поэтому компилятор преобразовал его в одноточную. Кодировка, которая была приведена, вероятно, была 0x3d6d9168, которая является общей кодировкой IEEE 754 для .058 в режиме с одной точностью.

Где-то в коде сборки, сгенерированном компилятором, компилятор сгенерировал директиву (инструкцию ассемблеру), которая заставляет это значение, 0x3d6d9168, храниться в памяти. (Это сложный процесс: ассемблер записывает значение в файл объекта, который он создает, поскольку часть различных данных является частью образа программы. Эти данные будут загружены в память, когда программа будет готова к выполнению или когда программа сначала пытается получить доступ к этой части памяти.)

Кроме того, компилятор сгенерировал команду fld dld ptr ds: [00415744h] ". Прошло некоторое время с тех пор, как я использовал эту форму сборки, поэтому я могу быть немного, но я считаю, что инструкция говорит «Использовать регистр данных (DS) в качестве базового адреса и 0x415744 как смещение внутри сегмента. Эта комбинация является указателем на двойное слово. Загрузите четыре байта оттуда в стек с плавающей точкой. (Стек с плавающей точкой представляет собой специальный набор регистров внутри процессора.)

Инструкция fstp, «fstp dword ptr [ebp-8]», означает «Возьмите содержимое регистра расширенного базового указателя (EBP)» и вычесть 8. Это значение является указателем на двойное слово. Храните четыре байта из стека с плавающей точкой в ​​это двойное слово и вытащите элемент из стека с плавающей точкой.

Обратите внимание, что 0x415744 не имеет ничего общего с значением с плавающей запятой. Это адрес в памяти, где хранилось постоянное значение.Эти две команды загружают постоянное значение из места только для чтения в памяти и сохраняют его на [ebp-8], который является местом в памяти, где компилятор решил сохранить значение в вашей переменной A. EBP обычно используется для обозначения местоположений в стеке, поэтому компилятор почти наверняка выделил некоторую память в фрейме стека этой функции для хранения значений ваших переменных.

Я подозреваю, что вы скомпилировали этот код с отключенной оптимизацией. Когда оптимизация включена, компилятор, скорее всего, не позаботится о том, чтобы фактически сохранить значение с плавающей запятой в памяти, назначенную для A. Это происходит потому, что вы ничего не делаете со значением сразу, просто сохраняя его в A. Но мы уже знаем значение и сохранить его в другом месте, так зачем его копировать? Вместо этого в каком-то более позднем месте в коде, где вы фактически используете значение A, компилятор затем загружает его из постоянной памяти и использует его непосредственно в вычислениях. (Это не всегда так: вы можете написать код, который требует от компилятора выполнить некоторое копирование, потому что ваш код может принимать один из нескольких возможных путей в зависимости от переданных ему параметров или других факторов, а компилятор должен выполнить копирование, чтобы обеспечить правильные данные используются для последующего пути. Однако в общем случае вам не следует ожидать точных совпадений между кодом C, который вы пишете и инструкциями по сборке, которые генерирует компилятор.)

Смежные вопросы