如何在x86程序集中划分浮点数? [英] How to divide floating-point number in x86 assembly?

查看:150
本文介绍了如何在x86程序集中划分浮点数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我尝试编写Heron算法来计算ECX寄存器中的sqrt时,它不起作用.看起来问题在于除以浮点数,因为结果是整数.

When i try to write Heron algorithm to count sqrt from ECX register, it doesn't work. It looks like the problem is dividing floating numbers, because the result is integer.

我的算法:

 sqrtecx:

MOV EDX, 10 ; loop count
MOV EAX, 5 ; x_0 in heron algorythm
MOV DWORD[EBP-100], ECX  ; save INPUT (ecx is input)    
MOV DWORD[EBP-104], EDX  ; save loop count
jmp     loop
MOV     ECX, EAX ; move  OUTPUT to ECX

loop:

MOV DWORD[EBP-104], EDX ; save loop count
xor edx, edx

MOV ECX, EAX
MOV     EAX, DWORD[EBP-100]
DIV ECX
ADD EAX, ECX
XOR EDX, EDX
mov ecx, 2
DIV ecx

MOV EDX, DWORD[EBP-104] ; load loop count
DEC EDX
JNZ loop

推荐答案

您需要使用浮点指令集来实现您的目标.您可能会觉得有用的一些说明是:

You need to use the Floating Point Instruction Set to achieve your goal. Some instructions you might find useful are:

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 st1 by st0, then pop from reg stack (again, push the result in st0)

这是一个简短的示例代码段(VS2010内联汇编):

Here's a short example snippet (VS2010 inline assembly):

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)
}


正如harold所指出的那样,还有一条指令可以直接计算平方根,即fsqrt.操作数和结果均为st0.


As harold pointed out, there's also an instruction which computes directly the square root, it is fsqrt. Both the operand and the result are st0.

编辑#2:
我不确定您是否真的可以将引用的立即值加载到st0没有明确指定.因此,我做了一个小片段来检查,结果是:

EDIT #2:
I wasn't sure if you really could load into st0 an immediate value as my reference doesn't specify if clearly. Therefore I did a small snippet to check and the result is:

    float res = 5.0 * 3 - 1;
000313BE D9 05 A8 57 03 00    fld         dword ptr [__real@41600000 (357A8h)]  
000313C4 D9 5D F8             fstp        dword ptr [res] 

这些是357A8h处的字节:

__real@41600000:
000357A8 00 00                add         byte ptr [eax],al  
000357AA 60                   pushad  
000357AB 41                   inc         ecx  

因此,我不得不得出一个结论,不幸的是,在加载和存储数字时,都必须将数字存储在主存储器中的某个位置.当然,如上所述并非必须使用堆栈,实际上,您也可以在数据段或其他地方定义一些变量.

So I have to conclude that, unfortunately, you have to store your numbers somewhere in the main memory both when loading and storing them. Of course using the stack as I suggested above isn't mandatory, in fact you could also have some variables defined in your data segment or somewhere else.

编辑#3:
不用担心,汇编是击败的强大野兽;)关于您的代码:

EDIT #3:
Don't worry, assembly is a strong beast to beat ;) Regarding your code:

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

您缺少fldfst的操作数.查看您的评论,我想您想要fld [esp]fst [esp],但是我不明白为什么您在谈论ebp. ebp应该保存堆栈帧的开头(其中很多内容我们不应该弄乱),而esp保存它的结尾.我们基本上希望在堆栈帧的末尾进行操作,因为在此之后,只是垃圾而已,没人在乎.
在计算并保存平方根之后,还应该在末尾add esp, 4.这是因为push ecx还会在sub esp, 4底下为您推入的值腾出空间,并且在保存回值时仍需要一些空间.正是为此,您也可以避免使用sub esp, 100add esp, 100,因为push已经为您腾出了空间.
最后一个警告":整数和浮点值以非常不同的方式表示,因此当您知道必须同时使用这两种类型时,请注意选择的指令.您建议的代码使用fldfst,它们都对浮点值进行操作,因此您得到的结果将不是您期望的结果.一个例子? 00 00 00 A9是169上的字节表示形式,但是它表示浮点数+ 2.3681944047089408408e-0043(对于那里比较挑剔的人,它实际上是一个长双精度数).
因此,最终的代码是:

You're missing the operands of fld and fst. Looking at your comments I suppose you wanted fld [esp] and fst [esp], I don't get why you're talking about ebp though. ebp is supposed to hold the beginning of the stack frame (where there's a lot of stuff which we shouldn't mess up with) whereas esp holds the end of it. We basically want to operate at the end of the stack frame because after it there's just junk no one cares about.
You should also add esp, 4 at the end, after you computed and saved the square root. This because push ecx does also sub esp, 4 under the hood to make room for the value you push and you still need some room when saving the value back. It's just for this that you can also avoid sub esp, 100 and add esp, 100, because the room is already made for you by push.
One last "warning": integers and floating point values are represented in very different ways, so when you know you have to use both types be careful about the instructions you choose. The code you suggested uses fld and fst, which both operate on floating point values, so the result you get won't be what you expect it to be. An example? 00 00 00 A9 is the byte representation on 169, but it represents the floating point number +2.3681944047089408e-0043 (for the fussy people out there it is actually a long double).
So, the final code is:

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

这篇关于如何在x86程序集中划分浮点数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆