您需要使用浮點指令集來實現您的目標。你可能會發現一些有用的指令是:
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)
}
編輯:
正如哈羅德指出的那樣,也是其計算的指令直接的平方根,它是fsqrt
。操作數和結果都是st0
。
編輯#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
所以我不得不得出結論,不幸的是,你必須在一些地方保存你的號碼在加載和存儲它們時都在主存中。當然,按照我上面的建議使用堆棧並不是強制性的,實際上你也可以在你的數據段或其他地方定義一些變量。
編輯#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 2012-01-10 14:32:57
@harold,在nasm組件中有一個平方根的指示?我沒有在我的CodeTable中。你能告訴我嗎? – 2012-01-10 15:24:57
用於FPU代碼的FSQRT(D9 FA),用於SSE的SQRTSS(F3 0F 51/r)和用於SSE2的SQRTSD(F2 0F 51/r)(也有帶4個打包漂浮物或2個打包雙打的版本)。下面是一個更完整的參考:http://siyobik.info/main/reference/ – harold 2012-01-10 15:46:18