Чтобы достичь своей цели, вам понадобится набор инструкций по плавающей запятой. Некоторые инструкции могут оказаться полезными являются:
fild <int> - loads and integer into st0 (not an immediate
faddp - adds st0 to st1, and pop from reg stack (i.e. result in st0)
fdivp - divides st0 by st1, then pop from reg stack (again, result in st0)
Вот краткий пример фрагмент кода (VS2010 встроенный ассемблер):
int main(void)
{
float res;
__asm {
push dword ptr 5; // fild needs a memory location, the trick is
fild [esp]; // to use the stack as a temp. storage
fild [esp]; // now st0 and st1 both contain (float) 5
add esp, 4; // better not screw up the stack
fadd st(0), st(0); // st0 = st0 + st0 = 10
fdivp st(1), st(0); // st0 = st1/st0 = 5/10 = 0.5
sub esp, 4; // again, let's make some room on the stack
fstp [esp]; // store the content of st0 into [esp]
pop eax; // get 0.5 off the stack
mov res, eax; // move it into res (main's local var)
add esp, 4; // preserve the stack
}
printf("res is %f", res); // write the result (0.5)
}
EDIT:
Гарольдом отметил, что есть также инструкция, которая вычисляет прямо квадратный корень, это fsqrt
. Оба операнда и результат: st0
.
EDIT # 2:
Я не был уверен, что если вы действительно можете загрузить в st0
непосредственное значение, как мой reference не указывает, если ясно. Поэтому я сделал небольшой фрагмент кода, чтобы проверить и результат:
float res = 5.0 * 3 - 1;
000313BE D9 05 A8 57 03 00 fld dword ptr [[email protected] (357A8h)]
000313C4 D9 5D F8 fstp dword ptr [res]
Эти байты в 357A8h
:
[email protected]:
000357A8 00 00 add byte ptr [eax],al
000357AA 60 pushad
000357AB 41 inc ecx
Так что я должен сделать вывод, что, к сожалению, вы должны хранить ваши номера где-то в основной памяти при загрузке и хранении. Конечно, использование стека, как я предложил выше, не является обязательным, на самом деле вы также можете иметь некоторые переменные, определенные в вашем сегменте данных или где-то еще.
EDIT # 3:
Не волнуйтесь, сборка сильный зверь бить;) Что касается кода:
mov ecx, 169 ; the number with i wanna to root
sub esp, 100 ; i move esp for free space
push ecx ; i save value of ecx
add esp,4 ; push was move my ebp,then i must come back
fld ; i load from esp, then i should load ecx
fsqrt ; i sqrt it
fst ; i save it on ebp+100
add esp,100 ; back esp to ebp
Вы упускаете операнды fld
и fst
. Глядя на ваши комментарии, я полагаю, вы хотели fld [esp]
и fst [esp]
, я не понимаю, почему вы говорите о ebp
. ebp
должен удерживать начало кадра стека (там, где есть много материала, с которым мы не должны испортиться), тогда как esp
удерживает его. Мы в основном хотим работать в конце фрейма стека, потому что после него есть просто мусор, о котором никто не заботится.
Вы должны также add esp, 4
в конце, после того как вы вычислили и сохранили квадратный корень. Это потому, что push ecx
делает также sub esp, 4
под капотом, чтобы освободить место для значения, которое вы нажимаете, и вам по-прежнему нужна некоторая комната при сохранении значения обратно. Только для этого вы также можете избежать sub esp, 100
и add esp, 100
, потому что комната уже создана для вас push
.
Последнее предупреждение: целые числа и значения с плавающей запятой представлены по-разному, поэтому, когда вы знаете, что вам нужно использовать оба типа, будьте осторожны с инструкциями, которые вы выберете. Предлагаемый код использует fld
и fst
, которые работают с плавающей точкой, поэтому результат, который вы получите, будет не таким, каким вы ожидаете. Пример? 00 00 00 A9 - это представление байтов на 169, но оно представляет число с плавающей запятой + 2.3681944047089408e-0043 (для суетливых людей это на самом деле длинный двойной).
Итак, окончательный код:
mov ecx, 169; // the number which we wanna root
push ecx; // save it on the stack
fild [esp]; // load into st0
fsqrt; // find the square root
fistp [esp]; // save it back on stack (as an integer)
// or fst [esp] for saving it as a float
pop ecx; // get it back in ecx
Существует инструкция для квадратных корней, кстати, как для кода FPU, так и для кода SSE. Таким образом, вам даже не нужно это делать. – harold
@harold. Есть ли место для квадратных корней в сборке nasm? У меня его нет в моей CodeTable. Вы можете мне это рассказать? –
FSQRT (D9 FA) для кода FPU, SQRTSS (F3 0F 51/r) для SSE и SQRTSD (F2 0F 51/r) для SSE2 (также есть версии, которые принимают 4 упакованных поплавка или 2 упакованных двойника). Вот более полная ссылка: http://siyobik.info/main/reference/ – harold